2

我正在尝试编写 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()。服务器就像一个回显服务器一样工作,并在收到消息后向客户端发送数据。这会导致死锁,服务器永远不会收到消息,客户端永远不会收到响应。可能是什么问题?期间会发生什么close(),该消息到达服务器?

4

1 回答 1

4

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

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

如果回显服务器使用第一种方法,它已经按预期工作了——所以我们可以打折扣。

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

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

从您的回答来看,它看起来像是添加了\n“修复”它。由此,我得出结论,您的 echo-server 是基于行的。所以有两种解决方案,第三种适用于任何情况:

  1. 使 echo-server 响应原始数据,而不是行
  2. 添加行尾标记
  3. 在客户端关闭出站流,即客户端到服务器的流(许多网络 API 允许您分别关闭出站和入站流)

另外:确保禁用 Nagle(通常称为 NO_DELAY) - 这将防止字节在客户端停留一段时间,等待组合成大小合适的数据包(这适用于 1 和 2,但不适用于 3;启用 Nagle 会添加延迟,但通常不会导致死锁)。

于 2012-11-19T12:05:14.487 回答