FTPS连接与文件传输
最近有使用FTPS传输文件的需求, python实现时遇到了一点问题,在这里做下记录
官方内置的ftplib库[1], 就是用来实现ftp连接的,里面有个类 ftplib.FTP_TLS则实现了ftps的连接, 但其实际却无法实现ftps连接
有以下一些坑点:
1. 一开始使用发现连接都无法建立, 直接stackoverflow[2]. 找到一个回答, 简要概括就是python的ftps没有在连接建立之后立刻包上SSL
2.改好之后, 尝试缺爆了个 “int XXX“ 的错误, 发现fplib版本与他们的不一样, 多了个context参数要补上
至此可以已经连接ftps了, 可以正常创建文件夹, 可以查看文件列表等,但是在传输文件时会发现无法传输...
3.查看传输方法, 发现一句这个:
if isinstance(conn, ssl.SSLSocket):
conn.unwrap()
我好不容易包了个ssl,你传文件又把我解开了, 任性
注释掉, 问题解决
最后贴下最简单的实现:
import ssl
import socket
from ftplib import FTP_TLS
class FTPS(FTP_TLS):
def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
certfile=None, context=None, timeout=60): # 注意当前版本的ftplib是否有context参数
FTP_TLS.__init__(self, host, user, passwd, acct, keyfile, certfile, context, timeout)
def connect(self, host='', port=0, timeout=-999):
'''Connect to host. Arguments are:
- host: hostname to connect to (string, default previous host)
- port: port to connect to (integer, default previous port)
'''
if host != '':
self.host = host
if port > 0:
self.port = port
if timeout != -999:
self.timeout = timeout
try:
self.sock = socket.create_connection((self.host, self.port), self.timeout)
self.af = self.sock.family
# add this line!!! # 这里要添加ssl
self.sock = ssl.wrap_socket(self.sock, self.keyfile, self.certfile, ssl_version=ssl.PROTOCOL_TLSv1)
# add end
self.file = self.sock.makefile('rb')
self.welcome = self.getresp()
except Exception as e:
print e
return self.welcome
def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
self.voidcmd('TYPE I')
conn = self.transfercmd(cmd, rest)
try:
while 1:
buf = fp.read(blocksize)
if not buf: break
conn.sendall(buf)
if callback: callback(buf)
# shutdown ssl layer
if isinstance(conn, ssl.SSLSocket):
pass # 这里不能取消ssl
# conn.unwrap()
finally:
conn.close()
return self.voidresp()
使用方式:
ftps = FTPS()
ftps.connect(host=HOST, port=PORT)
ftps.login(user=USERNAME, passwd=PASSWORD)
ftps.prot_p()
ftps.set_pasv(0) #我们这得关闭passive模式
ftps.storbinary("STOR {filename}".format(filename=filename), open(filepath, 'rb'))
因为一开始时间比较紧, 直接调shell解决的,这里也贴下:
调用shell运行:
command_map = "lftp -c 'open -e \"set ftps:initial-prot \"\"; \ " \
set ftp:ssl-auth TLS; \
set ftp:ssl-force true; \
set ftp:ssl-protect-data true; \
set ftp:passive-mode off; \
set ssl:verify-certificate no; \
# 这里放要用的指令, 别忘了最后要有个"收尾
# 如ls; "\
-u \"{USERNAME}\",\"{PASSWORD}\" {HOST_PORT} '"
[1] - ftplib document: https://docs.python.org/2.7/library/ftplib.html
[2] - stackoverflow: https://stackoverflow.com/questions/12164470/python-ftp-implicit-tls-connection-issue

浙公网安备 33010602011771号