python tcp socket - 为什么sendall消息只在close()之后发送

时间:2012-10-21 11:52:48

标签: python networking tcp blocking recv

我正在尝试编写perl TCP服务器/ python TCP客户端,现在我有了这样的代码:

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ("127.0.0.1", 9000)
sock.connect(server_address)

try:
    message = unicode('Test')
    sock.sendall(message)
    data = sock.recv(1024)
    print data
finally:
    sock.close()

我注意到,我的TCP服务器(用perl编写)不是在sendall(message)之后,而是在close()之后收到消息。服务器像echo服务器一样工作,并在收到消息后将数据发送到客户端。这会导致死锁,服务器永远不会收到消息,客户端永远不会得到响应。可能有什么问题?在close()期间会发生什么,该消息会发送到服务器?

1 个答案:

答案 0 :(得分:4)

我猜测这是由于服务器的实现造成的。编写echo服务器的方法有很多种:

  • 在循环(或异步回调)中接收字节,直到EOF;当收到字节时(每次循环迭代),在没有任何处理或缓冲的情况下回显它们;找到EOF时(入站流关闭),关闭出站流
  • 一次读取(假设它是文本协议),即查找CR / LF / EOF;找到一行时,返回该行 - 当找到EOF时(入站流关闭),关闭出站流
  • 读取到EOF ;然后返回所有内容并关闭出站流

如果echo服务器使用第一种方法,它将按预期工作 - 所以我们可以打折。

对于第二种方法,您正在发送文本但没有CR / LF,并且您还没有关闭从客户端到服务器(EOF)的流,因此服务器永远不会回复此请求。所以是的,它会陷入僵局。

如果是第三种方法,那么再次 - 除非你关闭出站流,它将会死锁

从您的回答中,看起来像添加\n“修复”它。从那以后,我得出结论,你的echo-server是基于行的。所以有两个解决方案,第三个解决方案适用于任何场景:

  1. 使echo-server响应原始数据,而不是行
  2. 添加行尾标记
  3. 关闭客户端的出站流,即客户端到服务器流(许多网络API允许您分别关闭出站和入站流)
  4. 此外:确保禁用Nagle(通常称为NO_DELAY) - 这将阻止位于客户端一段时间的字节,等待组成一个体面大小的数据包(这适用于1& 2,但不适用于3;启用Nagle会添加延迟,但通常不会导致死锁