Linuxで私のプロジェクトの1つにブロッキングソケットが使用されています。物事は非常に連続的に起こるので、ノンブロッキングは物事をより複雑にするだけです。とにかく、私は、recv()
コールが-1
で、errno
がEAGAIN
に設定されていることがよくあることがわかりました。ブロッキングソケットが返されます。EAGAIN
man
ページでは、ノンブロッキングソケットの場合にこのようなことが実際に言及されています。ノンブロッキングの場合、ソケットは使用可能な場合と使用できない場合がありますので、再試行する必要があります。
ブロッキングソケットの場合はどうなりますか?それを避けるために何かできますか?
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;
:現時点では
、それに対処するために私のコードは、この(私はそれがエラーに例外をスローしていますが、それを超えて、それはrecv()
周りに非常に単純なラッパーである)のようになりますこれは正しいですか?EAGAIN
の状態がかなり頻繁に発生します。
EDIT:これは関連性があるかもしれないことに気付いたものです。
私は
setsockopts()
を使用してソケットの読み取りタイムアウトを設定するのですが、それは30秒に設定されています。EAGAIN
は30秒に1回以上の頻度で起こります。 修正私のデバッグに欠陥があったので、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;
アイデアは、私はタイムアウトを強制することができるように接続を試みると、ソケットに選択し、ノンブロッキングにそれを設定することです。 setとrestoreの両方の呼び出しは正常に戻ります。したがって、この関数が完了すると、ソケットは再びブロックモードになります。
はい、それは30000ミリ秒に設定されていますが、私はEAGAINの*方法*をそれより頻繁に得ます。かなり驚異的。 –
*訂正*私のデバッグに欠陥があった、EAGAINは私が思ったほど頻繁に起こらなかった。おそらくタイムアウトがトリガーされます。 –