https://blog.csdn.net/chrisnotfound/article/details/80112736

上面的链接就是说明来 SO_KEEPALIVE 选项 为什么还需要 在应用层开发 心跳协议的原因  包括分布式系统开发中也必须自己设计  应用层 心跳协议的开发   

熟悉基于TCP协议进行linux高性能、高并发服务端编程的朋友肯定应该知道每个文件描述符及其所占的资源对并发量的影响。

在这种7*24甚至*365不间断运行的服务器上,一个描述符被浪费,两个被浪费...如果被浪费的多了,那还何谈高并发,高性能。除去文件描述被正常占用的情况外,是什么导致了我们可用的文件描述符越来越少呢?

https://blog.csdn.net/gettogetto/article/details/76736371

什么是半开连接?

当客户端与服务器建立起正常的TCP连接后,如果客户主机掉线(网线断开)、电源掉电、或系统崩溃,服务器进程将永远不会知道(通过我们常用的select,epoll监测不到断开或错误事件),如果不主动处理或重启系统的话对于服务端来说会一直维持着这个连接,任凭服务端进程如何望穿秋水,也永远再等不到客户端的任何回应。这种情况就是半开连接,浪费了服务器端可用的文件描述符。

如何处理?

熟悉套接字通用选项的朋友一定已经有了想法。TCP套接字不是有个保持存活选项SO_KEEPALIVE嘛,如果在两个小时之内在该套接字的任何一个方向上都没数据交换,TCP就自动给对端发送一个保持存活探测分节,如果此TCP探测分节的响应为RST,说明对端已经崩溃且已经重新启动,该套接字的待处理错误被置为ECONNRESET,套接字本身则被关闭。如果没有对此TCP探测分节的任何响应,该套接字的处理错误就被置为ETIMEOUT,套接字本身则被关闭。

确实,这个选项确实可以处理我们前面遇到的TCP半开连接的问题,但是默认两小时间隔探测的实时性是不是差了些呢?

当然,我们可以通过修改内核参数改小时间间隔,完美了吧?

但是必须注意的是大多数内核是基于整个内核维护这些时间参数的,而不是基于每个套接字维护的,因此如果把无活动周期从两小时改为(比如)2分钟,那将影响到该主机上所有开启了此选项的套接字。

我想大家都不会愿意承担服务器端的这种不确定性吧。另外,心跳除了说明应用程序还活着(进程存在,网络畅通),更重要的是表明应用程序能正常工作。而SO_KEEPALIVE由操作系统负责探查,即便是进程死锁或有其他异常,操作系统也会正常收发TCP keepalive消息,而对方无法得知这一异常。

没关系,其实我们可以在应用层模拟SO_KEEPALIVE的方式,用心跳包来模拟保活探测分节。

由于服务器通常要承担成千上万的并发连接,所以肯定是由客户端在应用层进行心跳来模拟保活探测分节,客户端多次收不到服务器的响应时可终止此TCP连接,而服务端可监测客户端的心跳包,若在一定时间间隔内未收到任何来自客户端的心跳包则可以终止此TCP连接,这样就有效避免了TCP半开连接的情况。

在进行TCP高并发服务器开发时,有些规则仿佛是约定俗成的,很多朋友会依据这些规则去做,比如高并发TCP服务器中进行主动关闭的一方最好是客户端服务器端程序最好启用SO_REUSEADDR选项,但是很多人却不知所以然,我们为什么要这么做呢?


先上图

可以看到执行主动关闭端和被动关闭端的各个阶段的状态,今天咱的重点就是TIME_WAIT状态,可以看出TIME_WAIT状态是执行主动关闭的那一端产生的。

TIME_WAIT状态有两个存在的理由

  1. 可靠地实现TCP全双工连接的终止;

  2. 允许老的重复分节在网络中消逝;

第一个理由参考上图。 假设主动关闭端最终发送的ACK丢失了。对端将重新发送FIN,主动关闭端只有在维护状态信息的情况下才可以重新发送最终的那个ACK。如果不维护这个状态信息,主动关闭端将会响应一个RST,对端会将此响应标记为错误,所以不能进行正常的关闭。

第二个理由假设我们在ip A:端口B主机和ip C:端口D主机之间建立一个TCP连接。我们关闭这个连接,过一段时间在相同的IP地址和端口之间建立另一个连接。由于他们的IP地址和端口号都相同,所以如果上一个连接的老的重复分组再出现会影响新的连接。为了做到这一点,TCP将不会给处于TIME_WAIT状态的连接发起这个新的连接。这个持续时间如果大于MSL(IP数据报在因特网中的最大生存时间)

如果要满足以上实现,TIME_WAIT状态必须要有一定的持续时间,所以TIME_WAIT也被称为2MSL等待状态,一般持续时间在1分钟到4分钟之间。

高并发TCP服务器中进行主动关闭的一方最好是客户端:因为对于高并发服务器来说文件描述符资源是很重要的资源,如果对于每一个连接都要经历TIME_WAIT这个2MSL的时长,势必造成资源不能立马复用的浪费。虽然对于客户端来说TIME_WAIT状态会占用端口和句柄资源,但是客户端一般很少有并发资源限制,所以客户端执行主动关闭是比较合适的。

服务器端程序最好启用SO_REUSEADDR选项:我们想这样做一种情况,如果生产环境中服务端程序由于某种错误操作关闭了,我们肯定是要立马重启服务程序,但是TIME_WAIT还在占用着这些地址端口资源让你的服务起不来,那你着不着急。SOREUSEADDR这个选项正是允许地址端口的重复绑定。

网络编程中 TCP 半开连接和TIME_WAIT 学习的更多相关文章

  1. unp第七章补充之TCP半开连接与半闭连接

    半打开(Half-Open)连接和半关闭(Half-Close)连接.TCP是一个全双工(Full-Duplex)协议,因此这里的半连接"半"字就是相对于全双工的"全&q ...

  2. TCP半开连接与半闭连接

    半打开(Half-Open)连接和半关闭(Half-Close)连接.TCP是一个全双工(Full-Duplex)协议,因此这里的半连接"半"字就是相对于全双工的"全&q ...

  3. 网络编程中TCP基础巩固以及Linux打开的文件过多文件句柄的总结

    1.TCP连接(短链接和长连接) 什么是TCP连接?TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议. 当网络通信 ...

  4. Linux系统网络编程中TCP通讯socket--send导致进程被关闭

    https://blog.csdn.net/dsanmux/article/details/52083403 https://blog.csdn.net/u011425939/article/deta ...

  5. [转帖]关于网络编程中MTU、TCP、UDP优化配置的一些总结

    关于网络编程中MTU.TCP.UDP优化配置的一些总结 https://www.cnblogs.com/maowang1991/archive/2013/04/15/3022955.html 感谢原作 ...

  6. 浅谈TCP/IP网络编程中socket的行为

    我认为,想要熟练掌握Linux下的TCP/IP网络编程,至少有三个层面的知识需要熟悉: 1. TCP/IP协议(如连接的建立和终止.重传和确认.滑动窗口和拥塞控制等等) 2. Socket I/O系统 ...

  7. 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系

    [Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...

  8. 用java网络编程中的TCP方式上传文本文件及出现的小问题

    自己今天刚学java网络编程中的TCP传输,要用TCP传输文件时,自己也是遇到了一些问题,抽空把它整理了一下,供自己以后参考使用. 首先在这个程序中,我用一个客户端,一个服务端,从客户端上传一个文本文 ...

  9. Fixed-Length Frames 谈谈网络编程中应用层(基于TCP/UDP)的协议设计

    http://blog.sina.com.cn/s/blog_48d4cf2d0101859x.html 谈谈网络编程中应用层(基于TCP/UDP)的协议设计 (2013-04-27 19:11:00 ...

随机推荐

  1. 整合SSM框架

    整合SSM 基本环境搭建 导入相关的pom依赖! <dependencies> <!--Junit--> <dependency> <groupId>j ...

  2. 万恶的NPE差点让我半个月工资没了

    引言 最近看到<阿里巴巴Java开发手册>(公众号回复[开发手册]免费获取)第11条规范写到: 防止 NPE ,是程序员的基本修养 NPE(Null Pointer Exception)一 ...

  3. 使用metadata-extractor获取照片中的位置、曝光度、大小...

    使用metadata-extractor实现获取图片中的属性信息 官网:https://drewnoakes.com/code/exif/ 简介:metadata-extractor允许您通过简单的A ...

  4. vue 导入.md文件(markdown转HTML)

    前言 刚接到这个需求的时候,觉得很简单(的确很简单)但是这玩意的坑真的也让人无奈. 网上找了很多的资料,都没有写出痛点(这就很难过了).通过实践并且在我们项目中平稳运行,想分享给后面的人 我的博客上也 ...

  5. [leetcode]669. Trim a Binary Search Tree寻找范围内的二叉搜索树

    根据BST的特点,如果小于L就判断右子树,如果大于R就判断左子树 递归地建立树 public TreeNode trimBST(TreeNode root, int L, int R) { if (r ...

  6. 解决使用Navicat等工具进行连接登录mysql的1130错误,无法使用Ip远程连接的问题(mysql为8.0版本)

    错误:ERROR 1130: Host '192.168.1.3' is not allowed to connect to thisMySQL serve 错误1130:主机192.168.1.3& ...

  7. 熬夜肝了一周!总结了这套对标阿里P8的java秘籍,限时发布3天!

    前言 最近老是有粉丝私信我说感觉自己学java越来越难了,这其中有刚毕业的应届生说自己的技术找不到满意的工作,也有在学校的大学习说找不到学习方式,更多的是正在工作的java开发人员说是现在的技术更新太 ...

  8. 一文彻底吃透MyBatis源码!!

    写在前面 随着互联网的发展,越来越多的公司摒弃了Hibernate,而选择拥抱了MyBatis.而且,很多大厂在面试的时候喜欢问MyBatis底层的原理和源码实现.总之,MyBatis几乎成为了Jav ...

  9. express安装问题

    步骤1 npm install -g express(全局安装express) (安装node就不必说了) 步骤2 npm install -g express-generator(安装命令工具) 完 ...

  10. SpringBoot项目,如何优雅的把接口参数中的空白值替换为null值?

    问题发生 我们公司代码生成的时候,查询列表统一都是使用了setEntity() ,查询写法如下: public List<BasReservoirArea> selectList(BasR ...