TCP 是面向连接的 , 在实际应用中通常都需要检测对端是否还处于连接中。如果已断开连接,主要分为以下几种情况:

1.连接的对端正常关闭,即使用 closesocket 关闭连接。

2.连接的对端非正常关闭,包括对端异常关闭,网络断开等情况。

对于第一种情况,很好判断,但是对于第二种情况,可能会要麻烦一些。在网上找到了一些文章,大致有以下两种解决方法:

自己编写心跳包程序

简单的说也就是在自己的程序中加入一条线程,定时向对端发送数据包,查看是否有 ACK ,如果有则连接正常,没有的话则连接断开。

使用 TCP 的 keepalive 机制

这个需要在 WinSock 编程时对当前 SOCKET 进行相应设置即可,比较方便。

为了方便起见,我这里采用 keepalive 机制,下面我就以 WinSock 上我实验得到的结果来大致讲一下其机理和使用方法。

首先说一下 keepalive 来判断异常断开的原理,其实 keepalive 的原理就是 TCP 内嵌的一个心跳包。

以服务器端为例,如果当前 server 端检测到超过一定时间(默认是 7,200,000 milliseconds ,也就是 2 个小时)没有数据传输,那么会 向client 端发送一个 keep-alive packet (该 keep-alive packet 就是 ACK 和当前 TCP 序列号减一的组合),此时 client 端应该为以下三种情况之一:

1. client 端仍然存在,网络连接状况良好。此时 client 端会返回一个 ACK 。 server 端接收到 ACK 后重置计时器,在2 小时后再发送探测。如果 2 小时内连接上有数据传输,那么在该时间基础上向后推延 2 个小时。

2. 客户端异常关闭,或是网络断开。在这两种情况下, client 端都不会响应。服务器没有收到对其发出探测的响应,并且在一定时间(系统默认为 1000 ms )后重复发送 keep-alive packet ,并且重复发送一定次数( 2000 XP 2003 系统默认为 5 次 , Vista 后的系统默认为 10 次)。

3. 客户端曾经崩溃,但已经重启。这种情况下,服务器将会收到对其存活探测的响应,但该响应是一个复位,从而引起服务器对连接的终止。

测试代码如下:

  1. #ifdef WIN32
  2. //#include <WS2tcpip.h>
  3. #include <mstcpip.h>
  4. #else
  5. #include <netinet/in.h>
  6. #include <netinet/tcp.h>
  7. #include <sys/types.h>
  8. #include <sys/socket.h>
  9. #include <arpa/inet.h>
  10. #endif
  11. void WanLanTcpClient::setKeepalive(int sock, int keepAlive, int keepInterval, int keepCount, int keepIdle)
  12. {
  13. #ifdef WIN32
  14. BOOL bKeepAlive = TRUE;
  15. int nRet = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
  16. (char*)&bKeepAlive, sizeof(bKeepAlive));
  17. if (nRet == SOCKET_ERROR)
  18. {
  19. ERROR_LOG("setsockopt failed: %d", WSAGetLastError());
  20. return;
  21. }
  22. // set KeepAlive parameter
  23. tcp_keepalive alive_in;
  24. tcp_keepalive alive_out;
  25. alive_in.keepalivetime = keepAlive; //3000ms
  26. alive_in.keepaliveinterval = keepInterval; //300ms
  27. alive_in.onoff = TRUE;
  28. unsigned long ulBytesReturn = ;
  29. nRet = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &alive_in, sizeof(alive_in),
  30. &alive_out, sizeof(alive_out), &ulBytesReturn, NULL, NULL);
  31. if (nRet == SOCKET_ERROR)
  32. {
  33. ERROR_LOG("WSAIoctl failed: %d/n", WSAGetLastError());
  34. return;
  35. }
  36. #else
  37.  
  38. //keepAlive = 1; //开启keepalive属性. 缺省值: 0(关闭)
  39. keepIdle = ; //如果在1秒内没有任何数据交互,则进行探测. 缺省值:7200(s)
  40. keepInterval = ; //探测时发探测包的时间间隔为1秒. 缺省值:75(s)
  41. keepCount = ; //探测重试的次数. 全部超时则认定连接失效..缺省值:9(次)
  42. setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));
  43. setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, (void*)&keepIdle, sizeof(keepIdle));
  44. setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (void*)&keepInterval, sizeof(keepInterval));
  45. setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (void*)&keepCount, sizeof(keepCount));
  46.  
  47. #endif
  48. }

TCP keepalive的机理及使用的更多相关文章

  1. TCP keepalive overview

    2. TCP keepalive overview In order to understand what TCP keepalive (which we will just call keepali ...

  2. 【转载】TCP保活(TCP keepalive)

    下图是我遇到tcp keepalive的例子: 以下为转载: TCP保活的缘起 双方建立交互的连接,但是并不是一直存在数据交互,有些连接会在数据交互完毕后,主动释放连接,而有些不会,那么在长时间无数据 ...

  3. TCP keepalive under Linux

    TCP Keepalive HOWTO Prev   Next 3. Using TCP keepalive under Linux Linux has built-in support for ke ...

  4. TCP keepalive

      2. TCP keepalive overview In order to understand what TCP keepalive (which we will just call keepa ...

  5. TCP连接探测中的Keepalive和心跳包. 关键字: tcp keepalive, 心跳, 保活

    1. TCP保活的必要性 1) 很多防火墙等对于空闲socket自动关闭 2) 对于非正常断开, 服务器并不能检测到. 为了回收资源, 必须提供一种检测机制. 2. 导致TCP断连的因素 如果网络正常 ...

  6. TCP Keepalive HOWTO

    TCP Keepalive HOWTO Fabio Busatto <fabio.busatto@sikurezza.org> 2007-05-04 Revision History Re ...

  7. 【 总结 】Tcp Keepalive 和 HTTP Keepalive 详解

    TCP Keepalive Tcp keepalive的起源          双方建立交互的连接,但是并不是一直存在数据交互,有些连接会在数据交互完毕后,主动释放连接,而有些不会,那么在长时间无数据 ...

  8. tcp keepalive选项

    之前一直对tcp keepalive选项理解有误, 以为通过setsockopt函数设置SO_KEEPALIVE和相关参数后该socket则使用设置的keepalive相关参数 否则使用系统默认的:k ...

  9. TCP长连接保持连接状态TCP keepalive设置

    如有转载,请注明出处:http://blog.csdn.net/embedded_sky/article/details/42077321 作者:super_bert@csdn 对于TCP长连接保活是 ...

随机推荐

  1. transform函数

    C++学习[原创]transform函数的应用 transform(first,last,result,op);//first是容器的首迭代器,last为容器的末迭代器,result为存放结果的容器, ...

  2. 页面跳转不带 referrer的方法

    如果页面中包含了如下 meta 标签,所有从当前页面中发起的请求将不会携带 referer: <meta name="referrer" content="neve ...

  3. IIS+PHP+MYSQL搭建

    以下安装过程是在win7环境下: mysql安装参照前面windows下的mysql zip格式安装.下面主要讲除mysql以外的安装. 一.IIS安装 确保CGI被安装. 二.IIs安装成功后,安装 ...

  4. light oj 1071 dp(吃金币升级版)

    #include <iostream> #include <algorithm> #include <cstring> #include <cstdio> ...

  5. git commit规范工具

    npm install -g commitizen commitizen init cz-conventional-changelog --save --save-exact 以后,凡是用到git c ...

  6. 约束布局ConstraintLayout加快布局速度

    Android Studio2.2更新布局设计器,同时,引人了约束布局ConstraintLayout. 简单来说,可以把它看做是相对布局的升级版本,但是区别与相对布局更加强调约束.何为约束,即控件之 ...

  7. Java虚拟机系列(五)---垃圾收集(GC)

    Java语言最大的优势除了它的平台无关性之外,还有它的自动内存分配和垃圾收集技术,本节我先来总结一下垃圾收集相关的内容.本文将从解答以下三个问题的角度来展开: 1.哪些内存需要回收? 2.什么时候回收 ...

  8. 通过Angular-cli创建新项目

    前提:已经安装Git 方法一:(推荐) 1.在需要创建项目的文件夹中右键打开 Git Bush Here ,在此输入  ng new ‘项目名’  --skip-install   (如下my-app ...

  9. String和StringBuffer的区别;字符串的一些基本方法

    String 和 StringBuffer区别 字符串广泛应用 在Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串. 需要注意的是,String的 ...

  10. Ajax和json一道基本的练习题

    关于ajax是javaEE中最基本的操作: 下面是这道题: 基本功能: jsp+servlet+ajax实现用户信息查询,实现无刷新删除 用户信息包括 学号 姓名 出生日期 性别 操作 2017010 ...