【问题标题】:How to connect to an FTP server with sockets?如何使用套接字连接到 FTP 服务器?
【发布时间】:2018-10-11 13:16:10
【问题描述】:

我正在尝试创建一个简单的 FTP 客户端,但无法建立 FTP 连接。

我使用了以下代码:

import socket 
sock = socket.socket() 
sock.connect(('localhost', 21)) 
data = 'USER adm\r\n'.encode() 
sock.send(data) 
print('Close') 
sock.close() 

我尝试连接的 FTP 服务器的日志如下所示:

(048507)01.05.2018 06:00:03 - (未登录) (127.0.0.1)> 已连接到端口 21,正在发送欢迎消息...
(048507)01.05.2018 06:00:03 - (未登录) (127.0.0.1)> 220-FileZilla Server 0.9.60 beta
(048507)01.05.2018 06:00:03 - (未登录) (127.0.0.1)> 220-由 Tim Kosse (tim.kosse@filezilla-project.org)
编写 (048507)01.05.2018 06:00:03 - (未登录) (127.0.0.1)> 220 请访问​​https://filezilla-project.org/
(048507)01.05.2018 06:00:03 - (未登录) (127.0.0.1)> 已断开连接。

我尝试发送USER adm 命令,但在日志中找不到它。如何使用套接字建立与 FTP 服务器的成功连接?

【问题讨论】:

  • 欢迎来到 SO!我编辑了标题结尾的问题文本,以使其对其他人更具可读性和可理解性。有关格式化的更多信息,请参阅editing help
  • 至少你需要用\r\n终止命令
  • 已添加\r\n,但问题未解决。
  • 到目前为止,您所做的只是发送用户名并关闭连接。假设该部分已正确完成。你认为下一步应该是什么? (或者,如果你看到一些证据表明它没有正确完成,请解释原因。)
  • 下一步是发送“PASS”和密码。但是我不能使用这个脚本发送“USER”。我认为 - 脚本发送数据,但它是编码的,并且 ftp 服务器不“理解”编码数据。但是 send() 仅适用于编码数据。当我使用 perl 脚本时, send() 发送字符串 - ftp 服务器获取此数据并将其显示在日志中。当我使用 python 脚本时,send() 需要编码数据 - ftp 服务器没有获取此数据(不在日志中显示)。

标签: python-3.x sockets ftp


【解决方案1】:

有几个可能的时间问题。

FTP 是一种“服务器先说话”的协议。您在日志中看到的 220 横幅是由服务器在接受连接后立即发送的。客户端应该在发送任何命令之前阅读该横幅。 (如果你得到220以外的任何数字代码,服务器都不愿意说话。)

出于测试目的,我建议您从服务器读取并将您读取的任何内容打印到标准输出。您的服务器的 220 横幅是多行 FTP 响应的示例,其中数字代码后跟第一行的连字符,最后一行是空格。您应该继续阅读,直到在数字代码后出现一行空格。

如果您不这样做,而只是在连接完成后立即发送USER,则您说话不正常。根据您的客户端代码运行的速度,服务器可能会在预期命令之前收到命令,这可以解释为什么它没有响应。

另一个可能的问题是您在发送USER 后立即关闭连接,而不是等待响应。服务器也可能注意到这一点。即使它没有尝试检测奇怪的客户端行为,它也可能在尝试发送响应时收到写入错误,这可以解释为什么它没有正常记录。

伪代码中的FTP客户端的整体结构是

connect
read response (banner)
while not done:
    send command
    read response
send QUIT
read response
close

(这省略了真正有趣的部分,即管理数据连接,但您还没有做到这一点)。

对于您只想达到USER 的测试,您至少需要:

connect
read banner
send USER
read response
close

(跳过QUIT 可能不会造成任何伤害)

请注意,允许服务器对任何命令返回多行响应,包括USER,因此您应始终检查数字代码后的空格。编写一个子程序来读取单个 FTP 响应并在每个命令之后调用它是个好主意。

【讨论】:

  • 是的,你说得对。我发送命令太快了。添加 time.sleep(5) 后它就可以工作了。
  • 我不认为我建议任何睡觉...阅读回复是正确的做法
【解决方案2】:

从服务器读取“第一个响应”以验证它是否“听到”您的声音,并且当服务器听到您的声音并且它“回话”一次时,循环读取来自服务器的所有响应,直到服务器安静下来,没有任何反应,就像等待它完成“谈话”一样。然后,您可以通过向服务器发送新数据来继续与服务器“对话”。

根据其他答案和您的评论回复,您似乎从忽略服务器本身何时完成“谈话”到期望它在 5 秒睡眠计时器后完成“谈话”,这并不好。最有效的方法是在作为客户端再次与服务器“交谈”之前“监听”服务器的所有“交谈”响应。

这样您就可以在服务器完成与您(客户端)“交谈”后立即与服务器“交谈”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-27
    • 2012-05-16
    • 2019-12-10
    • 1970-01-01
    • 2011-03-21
    • 1970-01-01
    相关资源
    最近更新 更多