4

我正在编写一个 C++ 客户端程序,通过互联网查询 postgreSQL 数据库。我想在等待答案时处理该事件,发生网络连接问题,因此客户端无法从数据库服务器接收任何消息。但是当我手动关闭互联网连接时,即使我稍后再次打开连接,程序仍然处于空闲状态。有没有办法捕捉这个事件或至少在客户端设置一个超时,以便它停止等待它之后的答案?

4

2 回答 2

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

最后,Richard Stevens 在他的“Unix Networking Programming”中展示的技术涉及系统中断的使用:

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);
        }
    }
}
于 2014-05-06T10:37:28.667 回答
0

在搜索了以下私有数据公共通道 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)。

于 2014-05-06T14:37:54.293 回答