[英]Is "reading zero bytes" from a socket a valid way for monitoring a TCP/IP disconnect in POSIX C?
我目前正在审查实现 POSIX sockets 的 C 应用程序。 此应用程序通过从套接字读取零字节来间歇性地检查与服务器的连接是否有效。 然后它检查是否设置了 errno 以确定连接是否正常。 这是一个强大的解决方案吗?
uint32_t IsConnected()
{
char dummy[10];
if(read(global_sockfd, dummy, 0) == -1)
{
if(errno != EWOULDBLOCK && errno != EAGAIN)
return FALSE;
else
return TRUE;
}
else
return TRUE;
}
不,这不是一个可靠的解决方案,原因有两个。
首先,对于已连接的 TCP 套接字,在读取所有传入数据并且远程对等方已关闭其连接端(使用close
或shutdown
)后, read
和recv
将返回零,而不是 -1。 在这种情况下,您的IsConnected
将返回 TRUE,这是错误的。
第二, read
的规范说(描述的第二段;所有强调我的)
在采取下述任何操作之前,如果
nbyte
为零,则read
function可能会检测并返回如下所述的错误。 在没有错误的情况下,或者如果没有执行错误检测,read
function 将返回零并且没有其他结果。
nbyte
是第三个参数,您的IsConnected
提供为零。 因此,取决于操作系统, IsConnected
可能总是返回 TRUE,而不管套接字的 state。
如果length
参数(相当于read
的nbyte
)为零, recv
的规范没有说明会发生什么。 我认为这可能是一个疏忽,它(和recvfrom
, recvmsg
等)旨在具有与read
相同的特殊行为。 因此,将read
更改为recv
本身并不能解决问题。 但是,我认为通过使用带有MSG_PEEK
的recv
可以实现完整的修复:
bool is_connected(int sock)
{
char dummy[1];
ssize_t nread = recv(sock, dummy, sizeof dummy, MSG_PEEK);
if (nread > 0)
return true; // at least one byte of data available
else if (nread == 0)
return false; // EOF
else
return errno == EWOULDBLOCK || errno == EAGAIN;
}
使用MSG_PEEK
允许您提供非零长度,因为实际上不会使用数据。
根据应用程序及其网络协议的详细信息,您可能还需要考虑在套接字上启用 TCP 保持活动数据包。
是的。 这在man 2 recv ,返回值部分中进行了解释:
这些调用返回接收到的字节数,如果发生错误,则返回 -1。 如果发生错误,则设置 errno 以指示错误。
当 stream 套接字对等体执行了有序关闭时,返回值为 0(传统的“文件结束”返回)。
各种域(例如,UNIX 和 Internet 域)中的数据报 sockets 允许零长度数据报。 当接收到这样的数据报时,返回值为 0。
如果从 stream 套接字接收的请求字节数为 0,则也可能返回值 0。
一个 TCP 套接字是一个 stream 套接字,所以只要你确保你的recv()
/ read()
调用使用非零大小的缓冲区,零返回表示对等方已执行有序关闭。
有序关闭是以下两种情况之一:关闭套接字,或在其上调用shutdown() (在这种情况下,使用 SHUT_WR 或 SHUT_RDWR,前者表示它不会发送任何进一步的数据但能够接收,后者表示它不会发送或接收任何数据)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.