python tcp套接字-为什么sendall消息仅在close()之后发送
我正在尝试编写perl TCP server/python TCP client,现在我有了这样的代码:python tcp套接字-为什么sendall消息仅在close()之后发送,python,networking,tcp,blocking,recv,Python,Networking,Tcp,Blocking,Recv,我正在尝试编写perl TCP server/python TCP client,现在我有了这样的代码: 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(messag
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()
过程中会发生什么,该消息会传到服务器?我想冒险猜测这是由于服务器的实现。有许多方法可以编写echo服务器:
- 在循环(或异步回调)中接收字节,直到EOF;在接收字节时(每次循环迭代),在不进行任何处理或缓冲的情况下对其进行回显;当发现EOF(入站流关闭)时,关闭出站流
- 一次读取行(假设它是文本协议),即查找CR/LF/EOF;找到行时,返回行-找到EOF时(入站流关闭),关闭出站流
- 读给一个EOF;然后返回所有内容并关闭出站流
如果echo服务器使用第一种方法,它将按照预期工作-因此我们可以对此打折
对于第二种方法,您正在发送文本,但没有CR/LF,并且您还没有关闭从客户端到服务器(EOF)的流,因此服务器将永远不会回复此请求。因此,是的,它将陷入僵局
如果是第三种方法,那么请再说一遍——除非关闭出站流,否则它将死锁
从您的回答来看,似乎添加了一个\n
“修复”了它。由此,我得出结论,您的echo服务器是基于线路的。因此,有两种解决方案,第三种解决方案适用于任何场景:
使echo服务器响应原始数据,而不是行
添加行尾标记
在客户端关闭出站流,即客户端到服务器流(许多网络API允许您分别关闭出站流和入站流)
另外:确保禁用Nagle(通常称为NO_DELAY)-这将防止字节在客户端停留一段时间,等待合成一个适当大小的数据包(这适用于1&2,但不适用于3;启用Nagle会增加延迟,但通常不会导致死锁).我冒险猜测这是由于服务器的实现。有许多方法可以编写echo服务器:
- 在循环(或异步回调)中接收字节,直到EOF;在接收字节时(每次循环迭代),在不进行任何处理或缓冲的情况下对其进行回显;当发现EOF(入站流关闭)时,关闭出站流
- 一次读取行(假设它是文本协议),即查找CR/LF/EOF;找到行时,返回行-找到EOF时(入站流关闭),关闭出站流
- 读给一个EOF;然后返回所有内容并关闭出站流
如果echo服务器使用第一种方法,它将按照预期工作-因此我们可以对此打折
对于第二种方法,您正在发送文本,但没有CR/LF,并且您还没有关闭从客户端到服务器(EOF)的流,因此服务器将永远不会回复此请求。因此,是的,它将陷入僵局
如果是第三种方法,那么请再说一遍——除非关闭出站流,否则它将死锁
从您的回答来看,似乎添加了一个\n
“修复”了它。由此,我得出结论,您的echo服务器是基于线路的。因此,有两种解决方案,第三种解决方案适用于任何场景:
使echo服务器响应原始数据,而不是行
添加行尾标记
在客户端关闭出站流,即客户端到服务器流(许多网络API允许您分别关闭出站流和入站流)
另外:确保禁用Nagle(通常称为NO_DELAY)-这将防止字节在客户端停留一段时间,等待合成一个适当大小的数据包(这适用于1&2,但不适用于3;启用Nagle会增加延迟,但通常不会导致死锁).您告诉它recv 1024字节,但只发送了4个。@stark:发送和接收是链接的,但操作是不同的。@user1040813:您绝对确定在调用.close()
之前不会发送数据吗?您是否与Wireshark等公司进行了核实?可能接收端正在缓冲等待线路端的数据,并在看到连接已关闭且不需要更多数据时取消该缓冲。这是很常见的。@LightnessRacesinOrbit我倾向于同意这是有责任的,但这取决于几个因素。。。我怀疑,很大程度上取决于服务器是如何编写的——这是我们看不到的。我们也许能够做出有根据的猜测,虽然是的,“问题”在于缓冲。关闭期间缓冲区被刷新,这就是为什么关闭后我收到消息。您告诉它recv 1024字节,但您只发送了4个。@stark:发送和接收是链接的,但操作不同。@user1040813:您绝对确定在调用.close()
之前不会发送数据吗?您是否与Wireshark等公司进行了核实?可能接收端正在缓冲等待线路端的数据,并在看到连接已关闭且不需要更多数据时取消该缓冲。这是很常见的。@LightnessRacesinOrbit我倾向于同意这是有责任的,但这取决于几个因素。。。我怀疑,很大程度上取决于服务器是如何编写的——这是我们看不到的。我们也许能够做出有根据的猜测,虽然是的,“问题”在于缓冲。在关闭过程中,缓冲区被刷新,这就是为什么关闭后我会收到消息。