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。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
#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() |