簡體   English   中英

從套接字“讀取零字節”是監控 POSIX C 中 TCP/IP 斷開連接的有效方法嗎?

[英]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 套接字,在讀取所有傳入數據並且遠程對等方已關閉其連接端(使用closeshutdown )后, readrecv將返回零,而不是 -1。 在這種情況下,您的IsConnected將返回 TRUE,這是錯誤的。

第二, read的規范說(描述的第二段;所有強調我的)

在采取下述任何操作之前,如果nbyte為零,則read function可能會檢測並返回如下所述的錯誤。 在沒有錯誤的情況下,或者如果沒有執行錯誤檢測read function 將返回零並且沒有其他結果。

nbyte是第三個參數,您的IsConnected提供為零。 因此,取決於操作系統, IsConnected可能總是返回 TRUE,而不管套接字的 state。

如果length參數(相當於readnbyte )為零recv的規范沒有說明會發生什么。 我認為這可能是一個疏忽,它(和recvfromrecvmsg等)旨在具有與read相同的特殊行為。 因此,將read更改為recv本身並不能解決問題。 但是,我認為通過使用帶有MSG_PEEKrecv可以實現完整的修復:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM