python 播放视频 ftp_在Python中连接到'通过TLS显式FTP'(??)

I cannot figure out how to see the file contents of an FTP site using ftplib.

I can connect to the FTP site using WinSCP just fine, and see the 6 files in the root directory.

In Python 3.4, I am using the following code:

from ftplib import FTP_TLS

ftps = FTP_TLS(timeout=100)

ftps.connect(ipAddress, 21)

ftps.auth()

ftps.prot_p()

ftps.login('username', 'password')

Which produces:

Out[72]: '230 User logged in.'

I can then run this:

ftps.pwd()

...and I see that I am in the root directory:

Out[73]: '/'

Everything seems to be gravy. BUT, when I try to see what is in the directory, using ftps.dir() or ftps.retrlines('NLST'), or anything else I have tried, I get a timeout:

TimeoutError: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond

I have googled around, and found several people saying it could be a 'passive vs active' connection setting problem. However, I asked the administrator of the FTP if it is passive or active, and he acted incredulous, just saying, "It's not SFTP. It is explicit FTP over TLS!!"

I am pretty ignorant of any of this. I am just trying to use ftplib (or any other package!) to connect to his FTP and download some files.

What am I missing??

EDIT:

I just figured out WinSCP is using passive mode, so that seems to be what works. As I understand it, ftplib is passive by default, but I went ahead and set the flag to true anyways. This did nothing, and I am still having the same issue.

I also checked my firewall (grabbing at straws), and it is completely turned off, so there should be no issues there.

I also tried sending explicit commands with the '.sendcmd()' method, which seems to be able to send commands, but will not grab any responses (or it cannot see the responses).

Is there some reason why I am able to see the directory I am in, but not any other data? I am obviously connected and talking to the server, and it would seem like the directory being available and viewable to me would imply data can go back and forth. Is the data possibly coming back in some way ftplib doesn't recognize? Any thoughts on where should I begin with troubleshooting this?

Finally, again, it seems like everything is setup correctly on their end, as I can see everything fine in WinSCP. What settings should I check to compare to ftplib?

EDIT 2:

As requested, I set the debug level (thanks for this tip), and below is the output:

ftps = FTP_TLS(timeout=15)

ftps.set_debuglevel(2)

ftps.connect(ipAddress, 21)

ftps.set_pasv(True)

ftps.auth()

ftps.prot_p()

ftps.login('username', 'password')

ftps.retrlines('NLST')

*get* '220 Microsoft FTP Service\n'

*resp* '220 Microsoft FTP Service'

*cmd* 'AUTH TLS'

*put* 'AUTH TLS\r\n'

*get* '234 AUTH command ok. Expecting TLS Negotiation.\n'

*resp* '234 AUTH command ok. Expecting TLS Negotiation.'

*cmd* 'PBSZ 0'

*put* 'PBSZ 0\r\n'

*get* '200 PBSZ command successful.\n'

*resp* '200 PBSZ command successful.'

*cmd* 'PROT P'

*put* 'PROT P\r\n'

*get* '200 PROT command successful.\n'

*resp* '200 PROT command successful.'

*cmd* 'USER username'

*put* 'USER username\r\n'

*get* '331 Password required for username.\n'

*resp* '331 Password required for username.'

*cmd* 'PASS ****************'

*put* 'PASS ****************\r\n'

*get* '230 User logged in.\n'

*resp* '230 User logged in.'

*cmd* 'TYPE A'

*put* 'TYPE A\r\n'

*get* '200 Type set to A.\n'

*resp* '200 Type set to A.'

*cmd* 'PASV'

*put* 'PASV\r\n'

*get* '227 Entering Passive Mode (10,19,1,137,195,128).\n'

*resp* '227 Entering Passive Mode (10,19,1,137,195,128).'

Traceback (most recent call last):

File "", line 8, in

ftps.retrlines('NLST')

File "C:\Anaconda3\lib\ftplib.py", line 467, in retrlines

with self.transfercmd(cmd) as conn,

File "C:\Anaconda3\lib\ftplib.py", line 398, in transfercmd

return self.ntransfercmd(cmd, rest)[0]

File "C:\Anaconda3\lib\ftplib.py", line 793, in ntransfercmd

conn, size = FTP.ntransfercmd(self, cmd, rest)

File "C:\Anaconda3\lib\ftplib.py", line 360, in ntransfercmd

source_address=self.source_address)

File "C:\Anaconda3\lib\socket.py", line 516, in create_connection

raise err

File "C:\Anaconda3\lib\socket.py", line 507, in create_connection

sock.connect(sa)

timeout: timed out

EDIT 3:

I tried to just set the passive flag to false, but when I ask for files, I get the following:

ftps.retrlines('NLST')

*cmd* 'TYPE A'

*put* 'TYPE A\r\n'

*get* '200 Type set to A.\n'

*resp* '200 Type set to A.'

*cmd* 'PORT 10,1,10,100,223,39'

*put* 'PORT 10,1,10,100,223,39\r\n'

*get* '501 Server cannot accept argument.\n'

*resp* '501 Server cannot accept argument.'

EDIT 4:

I enabled logging on WinSCP, and it looks like the helpful Steffen Ullrich was right! This was in the log for WinSCP:

< 2017-05-19 08:44:27.880 227 Entering Passive Mode (10,19,1,137,195,139).

< 2017-05-19 08:44:27.880 Server sent passive reply with unroutable address 10.19.1.137, using host address instead.

So, how do I get ftplib to do the same thing?

EDIT 5:

Found THIS - which is just rewriting the source to make it look to the host. Anyone else got a simpler, less intrusive/possibly-destructive way to do this?

As a second option, since the admin seems less than up to snuff, is there something explicit I can tell him to go do to the host to make this work better (i.e. - have passive return the correct IP)?

解决方案*get* '227 Entering Passive Mode (10,19,1,137,195,128).\n'

The problem is that the server is returning the wrong IP address inside the response to the PASV command. This is typical for servers in some internal network behind some firewall. In this case 10.19.1.137 is returned, which is an IP address usable in local networks only.

This is a broken setup of the FTP server. But unfortunately such broken setup is common so many clients work around it by ignoring the given IP address in the response and using instead the IP address of the control connection. ftplib has no support for such workaround. But one can monkey patch it to provide such support:

from ftplib import FTP_TLS

# replace original makepasv function with one which always returns

# the peerhost of the control connections as peerhost for the data

# connection

_old_makepasv = FTP_TLS.makepasv

def _new_makepasv(self):

host,port = _old_makepasv(self)

host = self.sock.getpeername()[0]

return host,port

FTP_TLS.makepasv = _new_makepasv

ftp = FTP_TLS(ipAddress)

ftp.login(...)

ftp.nlst()

This is successfully tested with Python 2.7.12 and Python 3.5.2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值