Sockets gevent tcp套接字已断开连接,但可以发送数据

Sockets gevent tcp套接字已断开连接,但可以发送数据,sockets,gevent,Sockets,Gevent,我有一个使用gevent编写的小型HTTP服务器,它接受传入的连接,并使用每连接greenlet发回数据。当(本地)客户端死亡时,尽管套接字处于关闭等待状态,服务器端对客户端的写入仍会成功: $ ls -l /proc/21860/fd |grep 22 lrwx------. 1 mathieu mathieu 64 Mar 21 19:55 22 -> socket:[187093] $ lsof |grep 187093 python 21860 mathieu

我有一个使用gevent编写的小型HTTP服务器,它接受传入的连接,并使用每连接greenlet发回数据。当(本地)客户端死亡时,尽管套接字处于关闭等待状态,服务器端对客户端的写入仍会成功:

$ ls -l /proc/21860/fd |grep 22
lrwx------. 1 mathieu mathieu 64 Mar 21 19:55 22 -> socket:[187093]
$ lsof |grep 187093
python    21860       mathieu   22u     IPv4             187093       0t0        TCP localhost.localdomain:36072->localhost.localdomain:48908 (CLOSE_WAIT)
现在,我希望我用gevent.socket.socket创建的套接字的send方法失败并出现异常,但我没有得到任何异常

def send(socket, data):
    sent = socket.send(data)
    while sent != len(data):
        data = data[sent:]
        sent = socket.send(data)

我的期望不正确吗?如果没有,这里会出什么问题?

经过一段时间的调试后,我对socket API在TCP之上的行为的预期是不正确的。潜在读者可能希望仔细阅读

要带走的东西:

  • 客户端close()将FIN发送到服务器,这大致意味着“我已向您发送完数据”。这意味着服务器可能仍然能够发回数据
  • 如果服务器在客户端关闭后尝试写入,写入将成功(返回从userspace复制到kernelspace的字节数),数据将发送到客户端,客户端将发送回RST,因为其套接字仍处于TIMEWAIT状态(除非您使用SO_LINGER zero禁用此选项,这就是您确实不希望将SO_LINGER设置为零的原因),否则服务器套接字状态将更新为关闭
  • 如果服务器在从客户端收到RST后尝试第二次写入,则写入将失败
  • 如果服务器在客户端关闭后尝试recv,recv将返回零以指示流结束
  • 总而言之,这意味着我的服务器需要使用返回为recv()==0的流结束通知作为客户端已关闭其连接并相应采取行动的标志(即关闭关联的套接字)