在第二次发送之前,Python不会检测到已关闭的套接字

时间:2011-02-04 15:17:48

标签: python sockets

当我关闭连接一端的套接字时,另一端在第二次发送数据时出错,但不是第一次:

import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("localhost", 12345))
server.listen(1)

client = socket.create_connection(("localhost",12345))
sock, addr = server.accept()
sock.close()

client.sendall("Hello World!")    # no error
client.sendall("Goodbye World!")  # error happens here

我尝试使用send代替sendall来设置TCP_NODELAY,检查fileno(),我找不到任何方法来获取第一个发送错误甚至是之后发现它失败了。 编辑:sock.shutdown之前调用sock.close无效。 编辑#2:甚至在结束之后和写作之前添加time.sleep并不重要。 编辑#3:检查send返回的字节数没有帮助,因为它总是返回消息中的字节数。

因此,如果我想检测错误,我可以提出的唯一解决方案是使用sendall跟随每个client.sendall(""),这会引发错误。但这似乎很苛刻。我在Linux 2.6.x上,所以即使解决方案只适用于该操作系统,我也会很高兴。

2 个答案:

答案 0 :(得分:13)

这是预期的,以及如何实现TCP / IP API(所以它几乎在所有语言和所有操作系统上都相似)

简短的说法是,如果send()调用以某种方式无法将数据传递到另一端,则无法保证send()调用直接返回错误。发送/写入调用只是将数据传递到TCP堆栈,并且由TCP堆栈决定是否可以提供数据。

TCP也只是一种传输协议,如果您需要知道您的应用程序“消息”是否到达另一端,您需要自己实现(某种形式的ACK),作为应用程序协议的一部分 - 没有其他免费午餐。

但是 - 如果你从套接字中读取(),你可以在发生错误时立即得到通知,或者当另一端关闭套接字时 - 你通常需要在某种形式的多路复用事件循环中这样做(即,使用select / poll或其他IO多路复用工具)。

请注意,您无法从套接字中读取()以了解最近的发送/写入是否成功,以下是几个案例的原因(但是这是一个没有想到的情况总能得到你)

  • 几个write()调用由于网络拥塞而被缓冲,或者因为tcp窗口关闭(可能是一个慢速阅读器)然后另一端关闭套接字或发生硬网络错误,因此你无法分辨如果,如果是最后一次没有通过的写作,或者是你在30秒前写的那篇。
  • 网络错误或防火墙静默丢弃您的数据包(不会生成ICMP回复),您必须等到TCP超时连接才能收到错误,该错误可能是几秒钟,通常是几分钟。
  • 当您调用send时,TCP正忙于重新传输 - 可能这些重新传输会产生错误。(与第一种情况完全相同)

答案 1 :(得分:1)

根据docs,请在致电sock.shutdown()之前致电sock.close()