我在Linux上的一個項目使用阻塞套接字。事情發生的非常連續,所以非阻塞會讓事情變得更加複雜。無論如何,我發現通常recv()
呼叫返回-1
與errno
設置爲EAGAIN
。阻塞套接字返回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
條件很常見。
編輯:我注意到一些可能相關的事情。
我設置使用
setsockopts()
在插座上的讀取超時,但它被設置爲30秒。每30秒發生一次的次數就會多於一次。 更正我的調試存在缺陷,EAGAIN
不像我想的那樣經常發生。也許是超時觸發。對於連接,我希望能夠連接超時,所以我暫時將套接字設置爲非阻塞。該代碼看起來是這樣的:
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;
的想法是,我將它設置爲非阻塞,嘗試連接,並選擇在插座上,所以我可以強制超時。設置和恢復fcntl()
調用都會成功返回,所以當此函數完成時,套接字應該再次處於阻止模式。
是的,但它設置爲30000毫秒,我比EAGAIN的*路*更頻繁。非常常態。 – 2009-04-09 18:24:12