You can use the select function described here: select (2) - Linux manual and here: windows API function
Note: fd = file descriptor, I'll call it descriptor
The select function works over several descriptors at the same time, it tests with a timeout if a given operation is available on the given descriptors, such descriptors are contained in
fd_set
structures, this structure is manipulated by the macros:
FD_ZERO
: Receives as parameter a fd_set and initializes it
FD_SET
: Receives as parameter a descriptor (its socket) and inserts it in the specified fd_set
FD_ISSET
: Overrides as a parameter descriptor and tests whether it is contained in fd_set
The function receives three fd_set's: the first contains the descriptors that will be used to test read operations, the second descriptors are for testing write operations, and the third ones for error checking. The first parameter of the function is a number that indicates the highest fd that is contained in all fd_set's passed plus one (this is ignored in windows). The last parameter is a timeval
structure that has two fields:
sec
: the time in seconds
usec
: the time in microseconds
The two together specify the time the function should wait until an operation is available. If you pass null
the function will lock until at least one operation is available.
When the function returns the last fd_set's will only contain the fd's that are available for the requested operation.
In windows the function is in the header: winsock2.h
(remembering that it replaces winsock.h
), already in linux you must include sys\select.h
and sys\time.h
, I think these are sufficient, however the link I reported uses:
/* According to POSIX.1-2001 */
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
Example usage:
enum OPERATION
{
READ = 0,
WRITE,
EXCEPTION
};
bool testOperation(uint16 sock, OPERATION operation, long milliseconds)
{
int r;
//o primeiro membro da struct é o tempo em segundos e o segundo é o tempo em microsegundos
struct timeval timeout = { milliseconds/1000, 0};
fd_set fds;
FD_ZERO(&fds);
FD_SET(sock, &fds);
switch (operation)
{
case READ:
//observe que é possível passar fd_set's nulos
r = select(sock + 1, &fds, NULL, NULL, &timeout);
break;
case WRITE:
r = select(sock + 1, NULL, &fds, NULL, &timeout);
break;
case EXCEPTION:
r = select(sock + 1, NULL, NULL, &fds, &timeout);
break;
}
if (r == SOCKET_ERROR){/*erro*/}
//operação está disponível
if (FD_ISSET(sock, &fds))
return true;
return false;
}
This is a code I had in github but I did not use the timeout, I edited now and I did not test the code because I'm at work and here I can not test it, but this should work, if not, it should at least direct you to the answer.
EDITED
I created two snippets in github to demonstrate use with two client / server programs:
client
server
The two use timeout, I only tested on windows.