簡體   English   中英

什么可能導致非阻塞套接字在“recv”上阻塞?

[英]What could cause a non-blocking socket to block on `recv`?

我有一個 TCP/IP 套接字設置為非阻塞,無論如何都是阻塞的。 套接字僅在一個線程中被引用。 此代碼適用於 Windows(有一些調用替換),但不適用於 Linux。 我有看起來像這樣的代碼(不要介意 C 風格的轉換——這是很久以前寫的。另外,我把它修剪了一點,所以如果我不小心修剪了一步,請告訴我。很有可能是我'我實際上在做那一步。實際代碼在另一台計算機上,所以我不能復制粘貼。):

// In the real code, these are class members. I'm not bonkers
int mSocket;
sockaddr_in mAddress;

void CreateSocket(
    unsigned int ipAddress,
    unsigned short port)
{        
    // Omitting my error checking in this question for brevity because everything comes back valid
    mSocket = socket(AF_INET, SOCK_STREAM, 0);  // Not -1

    int oldFlags = fctnl(mSocket, F_GETFL, 0);  // Not -1
    fcntl(mSocket, F_SETFL, oldFlags | O_NONBLOCK);  // Not -1

    mAddress.sin_family = AF_INET;
    mAddress.sin_addr.s_addr = ipAddress;  // address is valid
    mAddress.sin_port = htons((u_short)port);  // port is not 0 and allowed on firewall
    memset(mAddress.sin_zero, 0, sizeof(mAddress.sin_zero));

    // <Connect attempt loop starts here>
    connect(mSocket, (sockaddr*)&mAddress, sizeof(mAddress));  // Not -1 to exit loop
    // <Connect attempt loop ends here>
    // Connection is now successful ('connect' returned a value other than -1)
}

// ... Stuff happens ...

// ... Then this is called because 'select' call shows read data available ...
void AttemptReceive(
    MyReturnBufferTypeThatsNotImportant &returnedBytes)
{
    // Read socket
    const size_t bufferSize = 4096;
    char buffer[bufferSize];
    int result = 0;

    do {
        // Debugging code: sanity checks
        int socketFlags = fcntl(mSocket, F_GETFL, 0);  // Not -1
        printf("result=%d\n", result);
        printf("O_NONBLOCK? %d\n", socketFlags & O_NONBLOCK);  // Always prints "O_NONBLOCK? 2048"

        result = recv(mSocket, buffer, bufferSize, 0);  // NEVER -1 or 0 after hundreds to thousands of calls, then suddenly blocks

        // ... Save off and package read data into user format for output to caller ...
    } while (result == bufferSize);
}

我相信,因為 AttemptReceive 被調用以響應選擇,所以套接字恰好包含等於緩沖區大小(4096)倍數的字節數。 我已經用 printf 語句在一定程度上證實了這一點,所以它永遠不會在第一次循環時阻塞。 每次發生此錯誤時,在線程塊之前打印的最后兩行是:

result=4096
O_NONBLOCK? 2048

recv行更改為recv(mSocket, buffer, bufferSize, MSG_DONTWAIT); 實際上“修復”了這個問題(突然,recv 偶爾會返回 -1 並帶有 errno EWOULDBLOCK/EAGAIN(在我的操作系統上兩者相等)),但恐怕我只是在涌出的傷口上貼上創可貼,可以這么說。 有任何想法嗎?

PS地址是“localhost”,但我認為這並不重要。

注意:我使用的是 2010 年的舊編譯器(不是自己選擇的)g++ 4.4.7-23。這可能與問題有關。

socket()使用我的操作系統和編譯器自動在套接字上設置O_RDWR ,但似乎O_RDWR在程序開始時意外地在有問題的套接字上未設置(如果有數據要讀取,它以某種方式允許它正常讀取,否則阻塞)。 修復該錯誤導致套接字停止阻塞。 顯然, O_RDWRO_NONBLOCK都需要避免套接字阻塞,至少在我的操作系統和編譯器上是這樣。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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