How to set a timeout to receive a message from a server client with non-blocking mode?

I have a server with two SOCKET connections that are associated with clients , and I have determined that this server is non-blocking mode that does not stop when sending or receiving a message. I want to set a time for SOCKET for each connection, but if I use the following code:

  void getMessage(SOCKET connectedSocket, int time){ string error = R_ERROR; // Using select in winsock fd_set set; timeval tm; FD_ZERO(&set); FD_SET(connectedSocket, &set); tm.tv_sec = time; // time tm.tv_usec = 0; // 0 millis switch (select(connectedSocket, &set, 0, 0, &tm)) { case 0: // timeout this->disconnect(); break; case 1: // Can recieve some data here return this->recvMessage(); break; default: // error - handle appropriately. break; } return error; } 

My server is no longer non-blocking mode! I need to wait for the end of the 1st connection to receive a message from the 2nd connection! This is not what I expect! So, is there a way to set a timeout for non-blocking mode? Or should I handle this myself?

0
source share
1 answer

select is a demultiplexing mechanism. Although you use it to determine when data is ready for a single socket or timeout, it was actually intended to return data ready status on many sockets (hence fd_set ). In theory, this is the same with poll , epoll and kqueue . Combined with non-blocking I / O, these mechanisms provide the application writer with tools for implementing a single-threaded parallel server.

In my opinion, your application does not need such power. Your application will only handle two connections, and you are already using one thread for each connection. I believe that leaving the socket in I / O lock mode is more appropriate.

If you insist on non-blocking mode, my suggestion is to replace the select call with something else. Since what you want from select is an indicator of read or timeout readiness for a single socket, you can achieve a similar effect with recv passed with the appropriate parameters and with the corresponding timeout set in the socket.

 tm.tv_sec = time; tm.tv_usec = 0; setsockopt(connectedSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tm, sizeof(tm)); char c; swtich (recv(connectedSocket, &c, 1, MSG_PEEK|MSG_WAITALL)) { case -1: if (errno == EAGAIN) { // handle timeout ... } else { // handle other error ... } break; case 0: // FALLTHROUGH default: // handle read ready ... break; } 

From man recv :

MSG_PEEK - this flag causes the receive operation to return data from the beginning of the receive queue without removing this data from the queue. Thus, a subsequent receive call will return the same data.

MSG_WAITALL (since Linux 2.2). This flag requests that the work block be executed before the full request. However, the call may still return less data than requested if the signal is caught, an error or shutdown occurs, or the next data to be received is of a different type than the one returned.

As for why select behaves the way you noticed. Although the select call is thread safe, it is probably completely protected from reinstallation. Thus, one call to the select stream will be enabled only after the completion of another call to the stream ( select calls will be serialized). It is built into the demultiplexer function. Its purpose is to serve as the sole arbiter for whom the connections are ready. So he wants to control one thread.

+4
source

All Articles