【问题标题】:send is not sensing socket pending errors发送未感知套接字挂起错误
【发布时间】:2016-07-11 11:42:45
【问题描述】:

我的 TCP 客户端使用 tcp_keepalive_interval = 10stcp_keepalive_time = 1stcp_keepalive_probes = 10 实现了一个 keepalive 功能。

但是send 函数在连接断开超过 20 秒后没有发现任何错误。理想情况下,启用 keepalive,20 秒后 (keepalive_interval + keepalive_probes*keepalive_time) E_TIMEDOUT 应添加到套接字挂起错误中。

正如this 回答所说,

"read(2) 和 write(2) 都首先检索任何挂起的错误 甚至在尝试处理任何数据之前的套接字。”

当连接被keepalive关闭时,发送应该选择E_TIMEDOUT或任何套接字错误,但在下面的代码中没有发生。

    int sockfd = -1;
    if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
        cerr<<"ERROR: Failed to obtain Socket Descriptor!"<<endl;
        return -1;
    }

    //setting keepalive
    int optval;
    socklen_t optlen = sizeof(optval);

    //setting keepalive
    optval = 1;
    optlen = sizeof(optval);
    if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {
        cerr<<"set keepalive failed"<<endl;
        return -1;
    }
    //setting tcp_keepalive_intvl
    optval = 10;
    optlen = sizeof(optval);
    if(setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, &optval, optlen) < 0) {
        cerr<<"set tcp_keepalive_interval failed"<<endl;
        return -1;
    }
    //setting tcp_keepalive_time
    optval = 1;
    optlen = sizeof(optval);
    if(setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, &optval, optlen) < 0) {
        cerr<<"set tcp_keepalive_time failed"<<endl;
        return -1;
    }
    //setting tcp_keepalive_probes
    optval = 10;
    optlen = sizeof(optval);
    if(setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, &optval, optlen) < 0) {
        cerr<<"set tcp_keepalive_probe failed"<<endl;
        return -1;
    }

    struct sockaddr_in remote_addr;
    remote_addr.sin_family = AF_INET;
    remote_addr.sin_port = htons(#port_no);
    remote_addr.sin_addr.s_addr = inet_addr(#ip_addr);
    memset(&remote_addr.sin_zero, 0, 8);
    if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1) {
        cerr<<"Connect failed with ERRORNO "<<errno<<endl;
        return -1;
    } else {
        cout<<"TcpClient.cpp connected to server"<<endl;
    }
    while(1) {
        char data[20] = "hi hello";
        int ret = -1;
        if((ret = send(sockfd, data, 20, 0)) < 0) {
            cerr<<"TcpClient.cpp:- failed to send_data, ERROR CODE: "<<errno<<endl;
            return -1;
        } else if (ret == 0) {
            cout<<"send returns 0"<<endl;
        } else {
            cout<<"data sent"<<endl;
        }        
        sleep(1);
    }
    getchar();
    return 0;

我在一台带有 gcc 编译器的 linux 机器上测试了这段代码。 注意:我用recv 尝试了相同的代码,它巧妙地选择了E_TIMEDOUT 错误。

【问题讨论】:

    标签: sockets tcp


    【解决方案1】:

    你还没等多久。来自http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/usingkeepalive.html

    tcp_keepalive_time
    
        the interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe; after the connection is marked to need keepalive, this counter is not used any further 
    
    tcp_keepalive_intvl
    
        the interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime 
    
    tcp_keepalive_probes
    
        the number of unacknowledged probes to send before considering the connection dead and notifying the application layer 
    

    因此,如果您的值为 (10, 10, 10),keepalive 将在从对等方收到最后一个数据后 10 秒后开始。然后需要 10 个探测,每个探测间隔 10 秒,然后才能宣布连接失效。

    【讨论】:

    • 很抱歉错误地将 tcp_keepalive_time 称为 10s 而不是 1s。我已经编辑了这个问题。实际上我对keepalive参数的理解是正确的,但是我还缺少其他一些东西。
    猜你喜欢
    • 1970-01-01
    • 2015-09-13
    • 2014-10-02
    • 1970-01-01
    • 2015-08-27
    • 2014-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多