When writing a network application you can use non-blocking mode or blocking mode. Non blocking mode is more flexible and required when the application has to do multiple things, like servicing multiple sockets. If however the application is doing only 1 thing, for example reading from a socket and writing the data to a file or queue then using blocking mode can reduce your application’s complexity significantly. There is one small problem with blocking mode, if something goes wrong with the connection the application may never know; it will wait forever for data that will never arrive.
How can that happen? Imagine that your application has called recv and is waiting for data from a client. The client’s network connection is unreliable and the client application is experiencing multiple retransmissions. At some point the client’s TCP stack decides that the connection must be terminated; it notifies the client application and cleans up the socket. Your application is left waiting for data on a connection that as far as the client is concerned has been closed. The only way to clear the problem is to manually terminate your application and restart it. Terminating the application leaves the connected socket in a “TIME_WAIT” state that, unless you have set the REUSEADDR socket option, will prevent you from immediately restarting the application and having it bind to the listening socket.
You can however tell OpenVOS to set a time limit on how long to wait for data during the recv call. The result is that after the time limit expires the call will return a -1 and errno will be set to e$timeout (1081). Your application can then make a decision on how to proceed. It can terminate the connection, give the client another chance, send something to the client to test the connection, or any other application appropriate response. The point is that the diagnoses of the situation and the response are under your control.
The program timeout_recv.c in figure 2 is an example of how to do this. It takes 2 arguments, a port number to listen on and a timeout in units of 1/1024 of a second. Figure 1 shows an example execution, the command line (bold and underlined) is echoed because I am firm believer that all arguments should be echoed by interactive programs. Note I have set a 10 second (10240 / 1024) timeout. The program reports when it calls accept and if accept returns a timeout. While I didn’t mention it in the previous paragraph the timeout will work on the accept call as well and the program demonstrates that. After a connection is made it reports when it calls recv and the time that recv returned with either a timeout or characters. I have highlighted all the timeout messages.
Note that the calls to set the time limits are OpenVOS (and VOS) specific; this approach will not work under other operating systems.
timeout_recv 5647 10240
command line was: timeout_recv 5647 10240
timeout_recv: 12:14:27 calling accept
timeout_recv: 12:14:37 accept returned a timeout
timeout_recv: 12:14:37 calling accept
timeout_recv: 12:14:47 accept returned a timeout
timeout_recv: 12:14:47 calling accept
timeout_recv: 12:14:48 calling recv
timeout_recv: 12:14:58 recv returned a timeout
timeout_recv: 12:14:58 calling recv
timeout_recv: 12:15:00 recv return 1 characters
timeout_recv: 12:15:00 calling recv
timeout_recv: 12:15:10 recv returned a timeout
timeout_recv: 12:15:10 calling recv
timeout_recv: 12:15:16 recv return 1 characters
timeout_recv: 12:15:16 calling recv
timeout_recv: 12:15:23 recv return 1 characters
timeout_recv: 12:15:23 calling recv
timeout_recv: 12:15:30 recv return 1 characters
timeout_recv: 12:15:30 calling recv
timeout_recv: 12:15:38 recv return 1 characters
timeout_recv: 12:15:38 calling recv
timeout_recv: 12:15:46 recv return 1 characters
timeout_recv: 12:15:46 calling recv
timeout_recv: 12:15:56 recv returned a timeout
timeout_recv: 12:15:56 calling recv
timeout_recv: client terminated connection at 12:16:00