web-dev-qa-db-ja.com

recv関数へのタイムアウトの設定

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関数が戻るようにするにはどうすればよいですか?

12
vico

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...
    }
}
9
Nemanja Boric

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))
        //...
}
24
Remy Lebeau

fD_ISSET()マクロを使用して、読み取るデータがあるかどうかをテストします。 falseが返された場合、読み取りを行わないでください。

http://linux.die.net/man/3/fd_set

1
Richard Hodges