Узнайте, потеряно ли сетевое соединение, используя libpqxx

Я пишу клиентскую программу на C ++, запрашивающую базу данных postgreSQL через Интернет. Я хочу обработать событие, когда во время ожидания ответа возникает проблема с сетевым подключением, и поэтому клиент не может получать сообщения от сервера базы данных. Но когда я вручную отключаю интернет-соединение, программа остается бездействующей, даже если я снова включаю соединение позже. Есть ли способ перехватить это событие или хотя бы установить тайм-аут на стороне клиента, чтобы он перестал ждать ответа после него?

3

Решение

Вы можете установить таймаут для любой операции сокета (отличной от подключения), используя timeval структура и призыв к 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 опция используется для обозначения операции ввода.

Вы также можете сделать select вызовы неблокирующего сокета с параметром тайм-аута:

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 );

Наконец, методика, показанная Ричардом Стивенсом в его «Программировании Unix Networking», включает использование системных прерываний:

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);
}
}
}
2

Другие решения

После поиска вокруг следующего частные данные общедоступный канал 2 предложение использовать операции с сокетами я достиг следующего решения:

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);

Таким образом, через 10 секунд после того, как я отключился от сети, сокет начинает посылать зонды, чтобы убедиться, что соединение в порядке, и через некоторое время прерывает соединение и переопределяет on_abort() вызывается функция и после этого libpqxx пытается выполнить запрос. Количество повторов определяется вторым аргументом perform() функция (в данном случае 10).

0

По вопросам рекламы [email protected]