python sendall 未引发连接关闭错误
python sendall not raising connection closed error
我有以下代码,使用 python2.7 和 python3.5 测试,在 linux / mac 上,在远程和本地 mac海恩斯:
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')
另一边我有一个 "server" 运行 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')
因为您的 python 代码代表的客户端还不知道服务器的套接字已关闭并消失。将 TCP 连接视为两个独立的通道:每个方向一个。 TCP 协议允许每一方在自己选择的时间关闭连接的发送方。并且 TCP 无法向另一方指示未来在另一个方向发送的数据将不会被接受。
更详细... TCP 会话的普通终止涉及每个 方发送一个设置了FIN
标志的数据包。这表明发送 FIN
的对等方将不再发送任何数据。它确实 not 表示 FIN
数据包的接收方可能不会再发送任何数据。
所以,这里发生的是,当你杀死 netcat
时,一个 FIN
数据包从服务器端发送到客户端(并代表客户端由网络堆栈确认) .即关闭套接字的服务器=>客户端方向。但是,就客户端所知,客户端=>服务器方向仍然可用。稍后,当您的客户端尝试发送数据时,将发送一个包含数据的数据包。现在,服务器端的网络堆栈立即响应,通过发送 RST
数据包告诉客户端服务器不再存在。但是,您的 sendall
函数调用在收到时已经完成。
因此,如果您的客户要再睡一秒钟(或者实际上只是一秒钟的一小部分),然后尝试 另一个 发送,则后续发送 会引发异常。
创建整个会话的数据包捕获并使用 wireshark 对其进行研究可能会有所启发。 运行 在另一个 window 调用你的 python 代码之前(然后用 Ctrl-C 杀死):
sudo tcpdump -i lo -w /tmp/f.pcap port 8080
您也可以使用 wireshark 来捕获它,指定相同的 port 8080
作为捕获过滤器 -- 或 tcp.port == 8080
作为显示过滤器。
我有以下代码,使用 python2.7 和 python3.5 测试,在 linux / mac 上,在远程和本地 mac海恩斯:
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')
另一边我有一个 "server" 运行 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')
因为您的 python 代码代表的客户端还不知道服务器的套接字已关闭并消失。将 TCP 连接视为两个独立的通道:每个方向一个。 TCP 协议允许每一方在自己选择的时间关闭连接的发送方。并且 TCP 无法向另一方指示未来在另一个方向发送的数据将不会被接受。
更详细... TCP 会话的普通终止涉及每个 方发送一个设置了FIN
标志的数据包。这表明发送 FIN
的对等方将不再发送任何数据。它确实 not 表示 FIN
数据包的接收方可能不会再发送任何数据。
所以,这里发生的是,当你杀死 netcat
时,一个 FIN
数据包从服务器端发送到客户端(并代表客户端由网络堆栈确认) .即关闭套接字的服务器=>客户端方向。但是,就客户端所知,客户端=>服务器方向仍然可用。稍后,当您的客户端尝试发送数据时,将发送一个包含数据的数据包。现在,服务器端的网络堆栈立即响应,通过发送 RST
数据包告诉客户端服务器不再存在。但是,您的 sendall
函数调用在收到时已经完成。
因此,如果您的客户要再睡一秒钟(或者实际上只是一秒钟的一小部分),然后尝试 另一个 发送,则后续发送 会引发异常。
创建整个会话的数据包捕获并使用 wireshark 对其进行研究可能会有所启发。 运行 在另一个 window 调用你的 python 代码之前(然后用 Ctrl-C 杀死):
sudo tcpdump -i lo -w /tmp/f.pcap port 8080
您也可以使用 wireshark 来捕获它,指定相同的 port 8080
作为捕获过滤器 -- 或 tcp.port == 8080
作为显示过滤器。