为什么socket.send()会挂起?
我正在用Python写一个迷你FTP服务器,这个服务器把一个底层数据库当成FTP来使用。整个流程大概是这样的:
sock.send("150 Here's the file you wanted\r\n")
proc = Popen2(...)
for parts in data:
data_sock.send(parts)
proc.kill()
sock.send("226 There's the file you wanted\r\n")
data_sock.shutdown(0)
data_sock.close()
data_sock是一个正在运行的PASV套接字,Wireshark也确认了这一点。实际上发生的情况是,在第163,328个字节通过data_sock发送后,data_sock.send()这一行就卡住了。我怀疑发送缓冲区满了,但我不明白为什么FTP客户端不从PASV套接字读取数据。
我提到Popen2(...)这一行是因为我在OS X上复现了一个问题,链接在这里:http://bugs.python.org/issue3006,就是套接字在Popen进程被杀掉之前不会关闭。我不确定这是否有关系。
3 个回答
0
我在客户端上传的时候也遇到过类似的问题,感觉是调制解调器或路由器卡住了。目前我唯一能想到的解决办法就是控制传输速度(每次发送128个字节,然后暂停大约50毫秒,再继续发送)。
0
一个客户端停止读取数据的原因可能是有人在传输过程中拔掉了客户端的电源(或者断开了以太网线)。在这种情况下,TCP会不停地尝试重新发送数据包,可能会持续几分钟都没有收到回应,最后就放弃了。当然,还有其他可能的原因。
既然这些情况是你在想要建立一个稳定的服务器时必须面对的,真正的问题不是为什么会发生这些情况,而是当它们发生时你该怎么做。一些可能的解决办法包括:
- 确保客户端没有任何错误,导致它们在有数据可读时却停止读取。
- 确保服务器不会因为某个特定连接的发送操作被阻塞而停下来(你可以通过使用select()/poll()和非阻塞套接字来实现,或者可能通过多线程... 如果可以的话,我推荐前者)。
- 给select()添加一些超时逻辑,这样如果在某个套接字有数据准备发送但实际上没有发送超过(N)秒,服务器就会放弃并关闭这个套接字。(TCP本身也会这样做,但TCP的超时时间可能对你来说太长了)
1
从这段代码来看,具体情况不太清楚,也不知道客户端的情况,但有可能是你发送了150(表示一个新的数据通道),而不是125(表示使用现有的数据通道),这让客户端感到困惑,导致它根本不开始读取数据。
你有没有考虑过使用pyftpdlib,作为自己搭建服务器的一个替代方案?