A site for solving at least some of your technical problems...
A site for solving at least some of your technical problems...
The select() Unix command allows you to wait on an event on a set of file descriptions, in most cases, sockets.
The select() function accepts the following parameters:
The fd_set pointers are all optional. Actually, if all are set to NULL, select() waits for the specified timeout and then returns. Similarly, the timeout structure is optional, and if not present, select() blocks until something happens to one of those file descriptors.
So... up to here, not much of a problem, right?
Say you have a socket that you want to wait on. You are probably going to either be a receiver or a sender on that socket. So you want to either wait for data to have arrived (read fd_set) or for space in the buffer to write data (write fd_set). Therefore, in case of a socket, you might as well waits on both, read and write.
The problem is that if you put the file descriptor in both fd_set, read and write, you will wake up immediately if you have nothing to write to that file descriptor. If the only reason why you'd have to write something is because you receive something, then you generally do not need to wait for the write signal, only the read. If what you'd have to write may be bigger than the buffers offered by the system, then you want to look into using the wait on write but add that wait only if you still have data to write to the output. Otherwise, do not wait on the file descriptor write because there will be permanent room in its buffer and the select() will always return immediately and you'll end up with a tight loop.
So the idea is a forever loop that would look like this:
fd_set read_set; fd_set write_set; int r; struct timeval timeout; FD_ZERO(&read_set); FD_SET(file, &read_set); FD_ZERO(&write_set); if(my_output_buffer != NULL) { FD_SET(file, &write_set); } timeout.tv_sec = 300; // 5 minutes timeout.tv_usec = 0; r = select(file + 1, &read_set, &write_set, &read_set, &timeout); if(r == -1) { // handle error printf("select error!\n"); } else if(r == 0) { // IDLE ... do some other work printf("select timed out (5 min. passed)\n"); } else { if(FD_ISSET(file, &fd_read)) { // you can read data from that file descriptor } if(FD_ISSET(file, &fd_write)) { // you can write data to that file descriptor } }
Note that for the read and write to not block you may have to change the file descriptor to a NONBLOCK stream. Otherwise the read and/or write may block your process and the select() because less useful. Note that select() also works on sockets that use sendmsg() and recvmsg() (so called UDP sockets.)
The NONBLOCK, however, can be much harder to handle (especially if a server may receive a message such as a QUIT and quit immediately before all the pipes were read on the other side leaving the other processes without all the data they were expected to receive.)