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

标签 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() 之后获取消息。服务器的工作方式类似于回显服务器,在收到消息后将数据发送给客户端。这会导致死锁,服务器永远不会收到消息,客户端永远不会收到响应。可能有什么问题?在close()期间,该消息到达服务器时会发生什么?

最佳答案

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

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

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

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

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

从你的回答来看,看起来添加一个 \n “修复”它。由此,我得出结论,您的回显服务器是基于线路的。因此,有两个解决方案,第三个解决方案适用于任何场景:

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

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

关于python tcp socket - 为什么仅在 close() 之后发送 sendall 消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12997562/

相关文章:

python - 如何为用户赋予角色以使用react

c++ - poll() 是边缘触发函数吗?

multithreading - winsock 2. 同时发送的线程安全。 TCP

python - TCP 扫描器 Python 多线程

php - 如何在Python中解码使用gzip压缩的源代码

python - 从 django 中的 Imagefield 上传图像

javascript - 如何禁止访问我的服务器上的目录?

java - 文件上传流从哪里获取内容?

主框架Python背景色

linux - 我如何过滤从 whois 获得的结果?