0

Please note: the platform is Windows, not Linux.

I have a blocking TCP client socket. After connecting to the remote server, I set a read timeout (as the remote server is not stable, the network condition is bad) and then receive data.

Sometimes, the recv() function never returns and my program is dead.

The code looks like this:

// set timeout
{
    int millisec = 1000;
    if(setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, (char*)&millisec, sizeof(int))) {
        MessageBox(0, "setsockopt fail", "", 0);
    }
}

unsigned begin_t = time(0);
int r = recv(sock_, ptr, static_cast<int>(size), 0);
unsigned end_t = time(0);

if(end_t - begin_t > 2) {
    MessageBox(0, "over 2 sec", "", 0); // This MessageBox popups some time
}

I set the socket timeout to 1 second right before the recv() function. In theory, the recv() will never take more than 1 second. But sometimes, it still takes over 3 seconds, then the MessageBox appears.

Why is the timeout not working sometimes?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
aj3423
  • 2,003
  • 3
  • 32
  • 70
  • `time()` has seconds precision, so it is not going to be very accurate for timing code. Use `GetTickCount/64()` or `QueryPerformanceCounter()` instead – Remy Lebeau May 15 '19 at 16:27
  • Maybe I don't need to count the time cost, because sometimes it never returns. – aj3423 May 15 '19 at 16:57
  • There is simply no way that `recv()` can block forever when a non-infinite `SO_RCVTIMEO` timeout is in effect. So something else is going on. Also, just FYI, another way to implement a reading timeout is to call `select()` before calling `recv()`. – Remy Lebeau May 15 '19 at 18:35
  • Does the socket have the `OVERLAPPED` attribute? – Drake Wu May 16 '19 at 02:29

1 Answers1

1

SO_RCVTIMEO is no supported in a blocking socket.

If a blocking receive call times out, the connection is in an indeterminate state and should be closed. If the socket is created using the WSASocket function, then the dwFlags parameter must have the WSA_FLAG_OVERLAPPED attribute set for the timeout to function properly. Otherwise the timeout never takes effect.

Using the WSASocket with WSA_FLAG_OVERLAPPED. Or socket()(default for WSA_FLAG_OVERLAPPED mode)

Drake Wu
  • 6,927
  • 1
  • 7
  • 30
  • The key is exactly `WSA_FLAG_OVERLAPPED`, my code calls `setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,...`, The `WSA_FLAG_OVERLAPPED` is disabled if the `SO_OPENTYPE` is set. The detail can be found her: https://github.com/yhirose/cpp-httplib/issues/150 – aj3423 May 17 '19 at 16:46