为什么 Python 的 socket.recv() return -1

Why won't Python's socket.recv() return -1

如果我在来自客户端的 s.recv_into() 循环中关闭服务器套接字,我将无限地从 recv_into() 获取 0。

据我了解,知道套接字已关闭的唯一方法不是通过 Python 套接字机制本身,而是使用 select / poll / etc.

socket被对方关闭时不返回-1的原因是什么?为什么我不能正确区分 "no data currently" 和 "no one there anymore"?

编辑:

也许正确的问题是——如果对方终止了连接,为什么在使用 recv() 时没有抛出异常?

recv_into 只是名称为 recv 的 C 系统调用的包装器。 0的return值不是错误条件!

来自 Linux 手册,recv(2)

RETURN VALUE

These calls return the number of bytes received, or -1 if an error occurred. In the event of an error, errno is set to indicate the error.

When a stream socket peer has performed an orderly shutdown, the return value will be 0 (the traditional "end-of-file" return).

Datagram sockets in various domains (e.g., the UNIX and Internet domains) permit zero-length datagrams. When such a datagram is received, the return value is 0.

The value 0 may also be returned if the requested number of bytes to receive from a stream socket was 0.

对于错误情况,Python 不会 return -1,而是会引发适当的异常。

对于流式套接字,只要 recv_* return 的值表明已收到 0 个字节,就必须中断循环。检查 -1 没有意义,但如果您想更加确定,您自然可以使用 while sock.recv_into(....) > 0: 或类似的。

Python 中的各种 read 调用以类似的方式工作。

If I close a server socket while in a s.recv_into() loop from a client, I keep getting 0 from recv_into() infinitely.

是的,正如预期的那样。关闭的连接由 0 表示,而不是 -1。

As I understand, the only way to know a socket is closed was not through the Python socket mechanism itself, but using select / poll / etc.

不,那不是真的。只需以非阻塞模式调用 recv 即可完成这项工作,而无需涉及任何选择器机制。在非阻塞模式下,"no data yet" 状态将由适当的异常指示(请注意,您必须检查该异常,这不是 recv 抛出的唯一情况)。

但这并不意味着对等点仍然存在(默认 TCP 超时为 15 分钟 AFAIK)。这无法可靠地检测到。您能做的最好的事情就是通过网络实现一些 ping 协议。

What's the rational of not returning -1 when the socket is closed by the other side?

对于系统调用(例如 recv),-1 return 代码(通常)是为错误保留的。但是 Python 将这些转换为异常(所以 AFAIK 你永远不会在 Python 中得到 -1)。

总之0不是错误。这是对方关闭连接的信息。也许这是一个完全有效的情况,Python(或任何其他语言)无法知道这一点。