【问题标题】:Find out if network connection is lost using libpqxx使用 libpqxx 查看网络连接是否丢失
【发布时间】:2014-06-22 21:48:50
【问题描述】:

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

【问题讨论】:

    标签: c++ postgresql sockets networking libpq


    【解决方案1】:

    您可以使用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 网络编程”中展示的技术涉及系统中断的使用:

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

    【讨论】:

    • 我不知道如何准确地使用 setsockopt。我用 conn.sock() 写了完全相同的替换 sockfd ,它根本没有效果。
    【解决方案2】:

    在搜索了private data public channel 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)。

    【讨论】:

      猜你喜欢
      • 2013-09-02
      • 1970-01-01
      • 2015-12-27
      • 2014-09-03
      • 1970-01-01
      • 2020-05-08
      • 2015-07-27
      • 1970-01-01
      • 2011-01-13
      相关资源
      最近更新 更多