[英]Is "reading zero bytes" from a socket a valid way for monitoring a TCP/IP disconnect in POSIX C?
I'm currently reviewing a C application that implements POSIX sockets.我目前正在审查实现 POSIX sockets 的 C 应用程序。 This application intermittently checks to see if the connection to the server is valid by reading zero bytes from the socket.
此应用程序通过从套接字读取零字节来间歇性地检查与服务器的连接是否有效。 It then checks to see if an errno is set to determine whether or not the connection is okay.
然后它检查是否设置了 errno 以确定连接是否正常。 Is this a robust solution?
这是一个强大的解决方案吗?
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;
}
No, this is not a robust solution, for two reasons.不,这不是一个可靠的解决方案,原因有两个。
First, for a connected TCP socket read
and recv
will return zero, not −1, after all incoming data has been read and the remote peer has closed its end of the connection (using close
or shutdown
).首先,对于已连接的 TCP 套接字,在读取所有传入数据并且远程对等方已关闭其连接端(使用
close
或shutdown
)后, read
和recv
将返回零,而不是 -1。 Your IsConnected
will return TRUE in this case, which is wrong.在这种情况下,您的
IsConnected
将返回 TRUE,这是错误的。
Second, the specification of read
says (second paragraph of DESCRIPTION; all emphasis mine)第二,
read
的规范说(描述的第二段;所有强调我的)
Before any action described below is taken, and if
nbyte
is zero, theread
function may detect and return errors as described below.在采取下述任何操作之前,如果
nbyte
为零,则read
function可能会检测并返回如下所述的错误。 In the absence of errors, or if error detection is not performed , theread
function shall return zero and have no other results.在没有错误的情况下,或者如果没有执行错误检测,
read
function 将返回零并且没有其他结果。
nbyte
is the third argument, which your IsConnected
is supplying as zero. nbyte
是第三个参数,您的IsConnected
提供为零。 Therefore, depending on the operating system, IsConnected
might always return TRUE, regardless of the state of the socket.因此,取决于操作系统,
IsConnected
可能总是返回 TRUE,而不管套接字的 state。
The specification of recv
does not say anything about what happens if the length
argument (equivalent to nbyte
for read
) is zero;如果
length
参数(相当于read
的nbyte
)为零, recv
的规范没有说明会发生什么。 I think this is probably an oversight and it (and recvfrom
, recvmsg
, etc.) is meant to have the same special behavior as read
.我认为这可能是一个疏忽,它(和
recvfrom
, recvmsg
等)旨在具有与read
相同的特殊行为。 So changing read
to recv
will not fix the problem by itself.因此,将
read
更改为recv
本身并不能解决问题。 However, I think a complete fix is possible by using recv
with MSG_PEEK
:但是,我认为通过使用带有
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;
}
Using MSG_PEEK
allows you to supply a nonzero length, because the data will not actually be consumed.使用
MSG_PEEK
允许您提供非零长度,因为实际上不会使用数据。
Depending on the details of the application and its network protocol, you may also want to consider enabling TCP keep-alive packets on the socket.根据应用程序及其网络协议的详细信息,您可能还需要考虑在套接字上启用 TCP 保持活动数据包。
Yes.是的。 This is explained in man 2 recv , Return value section:
这在man 2 recv ,返回值部分中进行了解释:
These calls return the number of bytes received, or -1 if an error occurred.
这些调用返回接收到的字节数,如果发生错误,则返回 -1。 In the event of an error, errno is set to indicate the error.
如果发生错误,则设置 errno 以指示错误。
When a stream socket peer has performed an orderly shutdown, the return value will be 0 (the traditional "end-of-file" return).
当 stream 套接字对等体执行了有序关闭时,返回值为 0(传统的“文件结束”返回)。
Datagram sockets in various domains (eg, the UNIX and Internet domains) permit zero-length datagrams.
各种域(例如,UNIX 和 Internet 域)中的数据报 sockets 允许零长度数据报。 When such a datagram is received, the return value is 0.
当接收到这样的数据报时,返回值为 0。
The value 0 may also be returned if the requested number of bytes to receive from a stream socket was 0.
如果从 stream 套接字接收的请求字节数为 0,则也可能返回值 0。
A TCP socket is a stream socket, so as long as you make sure your recv()
/ read()
call uses a buffer with nonzero size, a zero return indicates the peer has performed an orderly shutdown.一个 TCP 套接字是一个 stream 套接字,所以只要你确保你的
recv()
/ read()
调用使用非零大小的缓冲区,零返回表示对等方已执行有序关闭。
An orderly shutdown is one of two things: closing the socket, or calling shutdown() on it (in this case, with either SHUT_WR or SHUT_RDWR, former indicating it will not send any further data but is able to receive, and the latter indicating it will not send or receive any data).有序关闭是以下两种情况之一:关闭套接字,或在其上调用shutdown() (在这种情况下,使用 SHUT_WR 或 SHUT_RDWR,前者表示它不会发送任何进一步的数据但能够接收,后者表示它不会发送或接收任何数据)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.