recv
関数を使用してソケットから読み取りました。読み取り可能なデータがない場合、問題が発生します。私のプログラムは停止します。 select
関数を使用してタイムアウトを設定できることがわかりました。ただし、タイムアウトはselect関数自体に影響を与え、selectが継続して待機するrecv
に影響するようです。
fd_set set;
struct timeval timeout;
FD_ZERO(&set); /* clear the set */
FD_SET(s, &set); /* add our file descriptor to the set */
timeout.tv_sec = SOCKET_READ_TIMEOUT_SEC;
timeout.tv_usec = 0;
int rv = select(s, &set, NULL, NULL, &timeout);
if((recv_size = recv(s , rx_tmp , bufSize ,0)) == SOCKET_ERROR)
{
...
}
タイムアウト後にrecv
関数が戻るようにするにはどうすればよいですか?
select
の戻り値を確認する必要があります。 select
は、タイムアウトが切れた場合に0
を返します。したがって、エラーを確認し、recv
が正の値を返した場合にのみselect
を呼び出す必要があります。
成功すると、select()およびpselect()は、返された3つの記述子セットに含まれるファイル記述子の数(つまり、readfds、writefds、exceptfdsに設定されたビットの総数)を返します。何か面白いことが起こる前に。
int rv = select(s + 1, &set, NULL, NULL, &timeout);
if (rv == SOCKET_ERROR)
{
// select error...
}
else if (rv == 0)
{
// timeout, socket does not have anything to read
}
else
{
// socket has something to read
recv_size = recv(s, rx_tmp, bufSize, 0);
if (recv_size == SOCKET_ERROR)
{
// read failed...
}
else if (recv_size == 0)
{
// peer disconnected...
}
else
{
// read successful...
}
}
recv()
を使用せずにselect()
自体にタイムアウトを設定する別の方法は、 setsockopt()
を使用してソケットのSO_RCVTIMEO
オプション(それをサポートするプラットフォーム)。
Windowsでは、コードは次のようになります。
DWORD timeout = SOCKET_READ_TIMEOUT_SEC * 1000;
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
//...
recv_size = recv(s, rx_tmp, bufSize, 0);
if (recv_size == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAETIMEDOUT)
//...
}
他のプラットフォームでは、コードは代わりに次のようになります。
struct timeval timeout;
timeout.tv_sec = SOCKET_READ_TIMEOUT_SEC;
timeout.tv_usec = 0;
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
//...
recv_size = recv(s, rx_tmp, bufSize, 0);
if (recv_size == -1)
{
if ((errno != EAGAIN) && (errno != EWOULDBLOCK))
//...
}
fD_ISSET()マクロを使用して、読み取るデータがあるかどうかをテストします。 falseが返された場合、読み取りを行わないでください。