检查非正常断开的tcp连接

    技术2023-03-19  51

    Tcp是面向连接的,在实际应用中通常都需要检测连接是否还可用.如果不可用,可分为:

    a. 连接的对端正常关闭.

    b. 连接的对端非正常关闭,这包括对端设备掉电,程序崩溃,网络被中断等.这种情况是不能也无法通知对端的,所以连接会一直存在,浪费国家的资源.

    tcp协议栈有个keepalive的属性,可以主动探测socket是否可用,不过这个属性的默认值很大.

    Linux方法:全局设置可更改/etc/sysctl.conf,加上:

    net.ipv4.tcp_keepalive_intvl = 20net.ipv4.tcp_keepalive_probes = 3net.ipv4.tcp_keepalive_time = 60

    在程序中设置如下:

    int keepAlive = 1; // 开启keepalive属性int keepIdle = 60; // 如该连接在60秒内没有任何数据往来,则进行探测 int keepInterval = 5; // 探测时发包的时间间隔为5 秒int keepCount = 3; // 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.

    setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));

    Windows方法:

    //定义结构及宏struct TCP_KEEPALIVE {u_longonoff;u_longkeepalivetime;u_longkeepaliveinterval;} ;

    #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)

    //KeepAlive实现TCP_KEEPALIVE inKeepAlive = {0}; //输入参数unsigned long ulInLen = sizeof(TCP_KEEPALIVE);

    TCP_KEEPALIVE outKeepAlive = {0}; //输出参数unsigned long ulOutLen = sizeof(TCP_KEEPALIVE);

    unsigned long ulBytesReturn = 0;

    //设置socket的keep alive为5秒,并且发送次数为3次inKeepAlive.onoff = 1; inKeepAlive.keepaliveinterval = 5000; //两次KeepAlive探测间的时间间隔inKeepAlive.keepalivetime = 5000; //开始首次KeepAlive探测前的TCP空闭时间

    if (WSAIoctl((unsigned int)s, SIO_KEEPALIVE_VALS,(LPVOID)&inKeepAlive, ulInLen,(LPVOID)&outKeepAlive, ulOutLen,&ulBytesReturn, NULL, NULL) == SOCKET_ERROR) {

    }

    在程序中表现为,当tcp检测到对端socket不再可用时(不能发出探测包,或探测包没有收到ACK的响应包),select会返回socket可读,并且在recv时返回-1,同时置上errno为ETIMEDOUT

     

     

    补充一个查看tcp连接状态的例子:

     

    int tcp_state(int tcp_fd){ struct tcp_info info; int optlen = sizeof(struct tcp_info); if (getsockopt (tcp_fd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&optlen) < 0) { printf ("getsockopt() TCP_INFO error/n"); exit (0); }printf ("%d/n",info.tcpi_state); if (info.tcpi_state == TCP_ESTABLISHED) return 0; /* ESTABLISHED */ else return -1;}

     

    最新回复(0)