FTP一般流程
FTP對應PASV和PORT兩種訪問方式,分別為被動和主動,是針對FTP服務器端進行區分的,正常傳輸過程中21號端口用于指令傳輸,數據傳輸端口使用其他端口。
PASV:由客戶端發起數據傳輸請求,服務器端返回并攜帶數據端口,并且服務器端開始監聽此端口等待數據,為被動模式;
PORT:客戶端監聽端口并向服務器端發起請求,服務器端主動連接此端口進行數據傳輸,為主動模式。
其中TYPE分兩種模式,I對應二進制模式、A對應ASCII模式;
PASV為客戶端發送請求,之后227為服務器端返回操作碼表示成功,并且后面帶有服務器端監聽的端口:143x256(左移8位)+48
之后通過STOR命令進行數據下載,下載完成后返回226表示數據傳輸完成。
2. Python代碼實現:
中文路徑問題:由于FTP支持ASCII編碼,Python ftplib中編碼方式使用latin-1,而window默認編碼方式為gbk,所以使用Python處理時需先將中文路徑編碼為gbk之后譯碼為latin-1字符;
上傳下載使用storline和retrline,對應二進制使用storbinary和retrbinary。對于stor類函數后面的參數fp表示接收一個文件對象,支持read方法,一般為打開需要上傳的源文件,而retr類函數后面的參數表示對于返回數據的處理方法。
從一個FTP服務器到另一個FTP服務器的數據傳輸:
利用本地電腦作為數據緩存,但并不將數據保存到硬盤,只在內存中存儲進行數據傳輸;其中一端作為下載一端為數據上傳。
首先登陸兩個FTP服務器,transfercmd函數用于發送命令并返回已建立好連接的本地Socket,此時分別在兩個本地Socket進行數據的收發即可。
在測試中發現,在發送完一個文件之后只有及時的關閉socket,21端口才會返回226,數據完成指示,這樣才可以循環下一個文件,在完成之后要退出FTP。
#coding=utf-8
import ftplib,os.path,os
import socket
f1=ftplib.FTP('172.16.2.76')
f2=ftplib.FTP('172.16.25.153')
class myFTP:
path='file/download/bbb/'
# ftplib中編碼使用latin-1
title='版本'.encode(encoding='gbk').decode(encoding='latin-1')
path1=path+title
localDir='E:\\ver\\fp\\'
path2='abc/edf/'
def __init__(self):
try:
f1.login('username','password')
except ftplib.error_perm:
print('f1 cannot loggin!')
return
try:
f2.login()
except ftplib.error_perm:
print('f2 cannot loggin!')
return
def ftpD(self):
filelist=[]
fileLIST=[]
filels=f1.retrlines('LIST %s'%(self.path1),callback=filelist.append)
f1.cwd(self.path1)
for file in filelist:
fileAttr=file.split(' ')
fileName=fileAttr[-1]
fileType=fileAttr[0][0]
if fileType=='-':
fileLIST.append(fileName)
for file in fileLIST:
path=self.localDir+file
f1.retrbinary('RETR %s'%(file),open(path,'wb').write)
print('%s download.....'%(file))
f1.quit()
def ftpU(self,fun=1):
os.chdir(self.localDir)
fileList=os.listdir()
# upload file
if fun==1:
for file in fileList:
path=self.path2
f2.storbinary('STOR %s'%(path+file),open(file,'rb'))
print('%s uploading......'%(file))
#delete file
if fun==0:
try:
for file in fileList:
path=self.path2
f2.delete(path+file)
print('%s delete......'%(file))
except ftplib.error_perm:
print('no file to delete!!')
return
f2.quit()
def test(self):
f1.cwd(self.path1)
f2.cwd(self.path2)
fileList=f1.nlst()
print(fileList)
for file in fileList:
print('transfer %s......'%(file))
f1.voidcmd('TYPE I')
f2.voidcmd('TYPE I')
sock1=f1.transfercmd('RETR %s'%(file))
sock2=f2.transfercmd('STOR %s'%(file))
while 1:
data=sock1.recv(1024)
sock2.sendall(data)
if len(data)==0:
break
# 數據發送完成后需關閉socket,服務器21端口才會有返回
sock1.close()
sock2.close()
res1=f1.getresp()
#print('f1 >> %s'%(res1))
res2=f2.getresp()
#print('f2 >> %s'%(res2))
f1.quit()
f2.quit()
if __name__=='__main__':
ftptest=myFTP()
ftptest.ftpU(0)
#ftptest.test()
#ftptest.ftpD()
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

