I 'm writing a C++ client program quering a postgreSQL database via the internet. I want to handle the event when while waiting for an answer, a network connection problem occurs and so the client can't receive any messages from the database server. But when I manually turn off the internet connection the program remains idle even if I turn the connection on again later. Is there a way to catch this event or at least set a timeout on client-side so that it stops waiting for an answer after it?
2 Answers
You can set a timeout for any socket operation (different from connect) using timeval
structure and call to setsockopt
.
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
if ( setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
sizeof(timeout)) < 0)
error( "setsockopt failed\n");
SO_RCVTIMEO
option is used to indicate input operation.
You can also make a select
calls to non blocking socket with a timeout parameter:
const int timeout_msecs = 5000;
struct timeval tval;
tval.tv_usec = 1000 * (timeout_msecs % 1000);
tval.tv_sec = timeout_msecs / 1000;
fd_set waitSet;
FD_ZERO( &waitSet );
FD_SET( fd, &waitSet );
int ret;
ret = select( fd + 1, &waitSet, NULL, NULL, &tval );
Finally, the technique showed by Richard Stevens in his "Unix Networking Programming" involves usage of system interrupts:
static void
sig_alrm(int signo)
{
return; /* just interrupt the recvfrom() */
}
void
dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
Signal(SIGALRM, sig_alrm);
while (Fgets(sendline, MAXLINE, fp) != NULL) {
Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
alarm(5);
// call recvfrom with 5 seconds timeout
if ( (n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) {
if (errno == EINTR)
fprintf(stderr, "socket timeout\n");
else
err_sys("recvfrom error");
} else {
alarm(0);
recvline[n] = 0; /* null terminate */
Fputs(recvline, stdout);
}
}
}

- 29,204
- 9
- 82
- 118
-
I can't figure out how to exactly use the setsockopt. I wrote exactly the same replacing sockfd with conn.sock() and it has no effect at all. – Angelos Makrygiorgos May 06 '14 at 11:49
After searching around following private data public channel 2 suggestion to use socket operations I've reached to the following solution:
pqxx::connection conn("host=blabla.com "
"port=5432 "
"user=abla "
"password=abla "
"dbname=ablabla");
const int val1 = 1;
if ( setsockopt(conn.sock(), SOL_SOCKET, SO_KEEPALIVE, &val1, sizeof(val1)) < 0){
perror( "setsockopt failed\n");
}
const int val2 = 5;
if ( setsockopt(conn.sock(), IPPROTO_TCP, TCP_KEEPCNT, &val2, sizeof(val2)) < 0){
perror( "setsockopt failed\n");
}
const int val3 = 2;
if ( setsockopt(conn.sock(), IPPROTO_TCP, TCP_KEEPINTVL, &val3, sizeof(val3)) < 0){
perror( "setsockopt failed\n");
}
const int val4 = 10;
if ( setsockopt(conn.sock(), IPPROTO_TCP, TCP_KEEPIDLE, &val4, sizeof(val4)) < 0){
perror( "setsockopt failed\n");
}
TransactorImpl transac();
conn.perform(transac,10);
This way 10 seconds after I disconnect from the network the socket starts sending probes to ensure the connection is OK and after a while it aborts the connection and my overriden on_abort()
function is called and after that libpqxx retries to execute the query. The number of retries is specified by the second argument of the perform()
function (in this case 10).

- 1
- 1

- 1,382
- 2
- 8
- 17