[英]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.