簡體   English   中英

堵頭返回EAGAIN

[英]Blocking socket returns EAGAIN

我在Linux上的一個項目使用阻塞套接字。 事情是非常連續地發生的,因此非阻塞只會使事情變得更加復雜。 無論如何,我發現通常recv()調用會返回-1並將errno設置為EAGAIN

man頁只真正提到了非阻塞套接字的這種情況,這是有道理的。 使用非阻塞,套接字可能會或可能不會,因此您可能需要重試。

是什么原因導致套接字阻塞? 我可以做些什么來避免它?

此刻,我處理它的代碼看起來像這樣(我讓它在錯誤時引發異常,但除此之外,它是一個非常簡單的環繞recv()包裝器):

int ret;
do {
    ret = ::recv(socket, buf, len, flags | MSG_NOSIGNAL);
} while(ret == -1 && errno == EAGAIN);


if(ret == -1) {
    throw socket_error(strerror(errno));
}
return ret;

這是正確的嗎? EAGAIN條件經常受到打擊。

編輯:我注意到的一些事情可能是相關的。

  1. 我確實使用setsockopts()在套接字上設置了讀取超時,但是將其設置為30秒。 EAGAIN發生的頻率比每30秒發生一次的頻率高。 更正我的調試有缺陷, EAGAIN的發生頻率不像我想象的那么頻繁。 也許是超時觸發。

  2. 對於連接,我希望能夠具有連接超時,因此我將套接字臨時設置為非阻塞。 該代碼如下所示:

     int error = 0; fd_set rset; fd_set wset; int n; const SOCKET sock = m_Socket; // set the socket as nonblocking IO const int flags = fcntl (sock, F_GETFL, 0); fcntl(sock, F_SETFL, flags | O_NONBLOCK); errno = 0; // we connect, but it will return soon n = ::connect(sock, addr, size_addr); if(n < 0) { if (errno != EINPROGRESS) { return -1; } } else if (n == 0) { goto done; } FD_ZERO(&rset); FD_ZERO(&wset); FD_SET(sock, &rset); FD_SET(sock, &wset); struct timeval tval; tval.tv_sec = timeout; tval.tv_usec = 0; // We "select()" until connect() returns its result or timeout n = select(sock + 1, &rset, &wset, 0, timeout ? &tval : 0); if(n == 0) { errno = ETIMEDOUT; return -1; } if (FD_ISSET(sock, &rset) || FD_ISSET(sock, &wset)) { socklen_t len = sizeof(error); if (getsockopt(SOL_SOCKET, SO_ERROR, &error, &len) < 0) { return -1; } } else { return -1; } done: // We change the socket options back to blocking IO if (fcntl(sock, F_SETFL, flags) == -1) { return -1; } return 0; 

我的想法是將其設置為非阻塞,嘗試連接並在套接字上進行選擇,以便強制超時。 set和restore fcntl()調用均成功返回,因此該函數完成后,套接字應再次以阻塞模式結束。

您可能在套接字上設置了非零的接收超時(通過setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,...) ),因為這也會導致recv返回EAGAIN

您使用的MSG_DONTWAIT是否有可能被指定為標志的一部分? man頁上說,如果沒有可用數據並且指定了此標志,則將發生EAGAIN

如果您確實想強制執行一個塊,直到recv()取得一定的成功,則可能希望使用MSG_WAITALL標志。

EAGAIN由操作系統生成,就像“糟糕!很抱歉打擾您。”。 如果發生此錯誤,您可以嘗試再次閱讀,這不是嚴重或致命的錯誤。 我已經看到這些中斷在Linux和LynxOS中發生,每天發生一次,每天發生100次。

我不建議您先嘗試此修復程序,但如果您沒有所有選擇,則始終可以在套接字上select()並保持相當長的超時時間,以強制其等待數據。

暫無
暫無

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

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