python sendall没有提高连接关闭错误

时间:2018-02-04 21:05:43

标签: python sockets network-programming

我在linux / mac上,在远程和本地机器上使用python2.7和python3.5测试了以下代码:

import socket
import time

s = socket.socket()
s.connect(("127.0.0.1", 8080))
s.sendall(b'first')
time.sleep(20)
s.sendall(b'should fail')
另一方面,我有一个"服务器"使用netcat -l -p8080

运行

一见到first,我就杀了netcat命令

但是s.sendall没有引发任何异常,为什么会这样呢?

编辑:请注意再次执行s.sendall然后提升异常

import socket
import time

s = socket.socket()
s.connect(("127.0.0.1", 8080))
s.sendall(b'first')
time.sleep(20)
s.sendall(b'should fail')
s.sendall(b'now it really fails')

1 个答案:

答案 0 :(得分:4)

因为你的python代码所代表的客户端还不知道服务器的套接字是关闭的并且已经消失了。将TCP连接视为两个独立的通道:每个方向一个。 TCP协议允许每一方在其自己选择的时间关闭其连接的发送侧。并且TCP无法向另一方表明将来不会接受将来向另一方向发送的信息。

更详细地说......普通终止TCP会话涉及每个侧发送一个设置了FIN标志的数据包。这表明发送FIN的对等方不会再发送任何数据。 not 表示FIN数据包的接收方可能不再发送任何数据。

所以,这里发生的事情是当你杀死netcat时,一个FIN数据包从服务器端发送到客户端(并由网络堆栈代表客户端确认)。这将关闭套接字的server =>客户端方向。但是,只要客户端知道,client =>服务器方向仍然可用。稍后,当您的客户端尝试发送数据时,将发送包含数据的数据包。现在,服务器端的网络堆栈立即响应,通过发送RST数据包告诉客户端服务器不再存在。但是,您的sendall函数调用会在收到的时间内完成。

因此,如果您的客户端再睡一秒钟(或者实际上只是一小部分时间),然后再尝试另一个发送,那么后续发送引发异常。

创建整个会话的数据包捕获并使用wireshark进行研究可能是有益的。在调用python代码之前在另一个窗口中运行它(然后使用Ctrl-C终止):

sudo tcpdump -i lo -w /tmp/f.pcap port 8080

您还可以使用wireshark捕获它,指定与捕获过滤器相同的port 8080 - 或tcp.port == 8080作为显示过滤器。