- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章四个实验,彻底搞懂TCP连接的断开由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
看到这个标题你可能会说,TCP 连接的建立与断开,这个我熟,不就是三次握手与四次挥手吗?且慢,脑海中可以先尝试回答这几个问题:
四次挥手是谁发起的?
如果断电/断网了连接会断开吗?
什么情况下没有四次挥手连接也会断开?
这不是面试,而是遇到了实际问题,至于是什么问题,容我先卖个关子,本文也不会解答,后面会有一篇专门的文章来说遇到的问题是啥,所以在讲实际问题之前,先弄懂理论.
我们由浅入深,先了解正常情况下 TCP 连接是如何断开的,下图为 TCP 三次握手与四次挥手的经典图(来自《TCP/IP详解卷1》) 。
在我们的电脑上,可以使用 python 的 SimpleHTTPServer 来快速起一个 http 服务(http 也是基于 TCP 协议),比如这样:
再通过 nc 或 telnet 这两个命令来创建 TCP 连接,比如我测试使用 nc 来创建连接 。
Connection to ip port [tcp/*] succeeded! 表示连接成功 。
我们如何观察这个连接呢?可以通过 netstat 或 lsof 来查看这条"连接",这里我使用 lsof(mac 与 Linux 系统的 netstat 命令不太一样,使用起来有点别扭 ) 。
无论是客户端还是服务端都会占用一个端口,不过服务端端口是固定的,客户端端口是随机的.
如果我们想看 TCP 连接和断开时握手与挥手的 TCP 报文怎么查看呢?可以使用 tcpdump 命令 。
为了方便查看,和上面的经典图放在了一起 。
这里的参数需要提一下的是 -S,如果不加 -S 参数看到的第三次握手的ack=1,与书上的理论不太一样,其实这里只是 tcpdump 简化了展示,想看实际值需要加 -S 。
这里的 Flags [S]/[S.]/[.] 。
命令与抓三次握手相同,我们抓到如下挥手数据 。
这张图有点奇怪,四次挥手居然变成了三次,这其实是 TCP 协议的实现问题,如果第二次与第三次挥手之间没有数据发送,那么被动断开连接的一方就可能会把第二次的 ACK 与 第三次的 FIN 合并为一次挥手.
当然我也抓到过正常的四次挥手,大概长这样 。
上面铺垫了这么多,现在开始进入正题.
我们来思考一个问题:TCP 连接的断开是谁发起的?程序本身还是操作系统?
我们来看一段非常简单的 TCP 连接创建与断开的代码 。
运行后,效果如下,也符合我们预期:当程序打印 Client connected! 时,能看到连接,当打印 Client connect closed! 时,连接断开 。
如果我们在连接断开前使用 kill -9 强杀进程呢?(这里我用了两台电脑来测试) 。
我们发现 conn.Close() 并没有执行,但四次挥手还是发生了.
查阅资料发现如下结论:
a、b 两个正常连接的对端进程。假如 b 进程没有调用 close 就异常终止,那么发送 FIN 包是内核 OS 代劳 。
我们通过上面的实验发现就算进程异常终止,操作系统也会帮忙发起四次挥手 。
但如果是断电或断网的情况下,操作系统就无法代劳了,这时会怎样呢?为了便于测试,这里用两台电脑,client 连接 server,断开 server 的网络来模拟断网断电情况.
可以肯定的是断网,断电后,连接不会立即断开,那么后续连接是否会断开呢?我们分成下面几种情况来看 。
断网时有数据传输 。
断网时如果有数据发送,由于收不到 ACK,所以会重试,但并不会无限重试下去,达到一定的重发次数之后,如果仍然没有任何确认应答返回,就会判断为网络或者对端主机发生了异常,强制关闭连接。此时的关闭是直接关闭,而没有挥手(数据都发不出去,还挥啥手),Linux 下的设置为 。
最小重传时间是200ms 最大重传时间是120s 重传次数为15 。
断网时没有数据传输 。
断网时如果没有数据传输,还得看 TCP 连接的 KeepAlive 是否打开,关于 TCP 的 KeepAlive 简介如下:
开启KeepAlive 。
操作系统中有这么几个参数控制 KeepAlive 的配置:
在 Linux 上可以通过如下文件查看 。
如果按照这个默认值来看,得2小时没有数据传输,KeepAlive 才开始工作.
而在 Go 中只有两个参数可以设置:
其中第二个 SetKeepAlivePeriod 源码是这样的:
SetKeepAlivePeriod 的参数同时设置了 tcp_keepalive_intvl 和 tcp_keepalive_time,tcp_keepalive_probes 没法设置 。
做个简单测试:client 开启 KeepAlive 连接 server 后,什么数据都不发送,把server 的网断掉,可以看到 KeepAlive 心跳包,一段时间后连接被置为 CLOSED 状态 。
关闭KeepAlive 。
关闭 KeepAlive 后,如果没有数据传输,连接永远不会断开 。
断网后 server 重启再恢复 。
再思考一个场景,如果 client 与 server 建立连接后,没有数据传输,断掉 server 端的网络,这时如果把 server 程序重启一下,再恢复网络,那这条连接还能用吗?
如果 server 重启后,client 还是不发数据,那这条连接看起来还是可用的,因为他们根本不知道对方是个什么情况,但如果此时 client 发送一点数据给 server,你会发现 server 会发送一个 RST 给client,然后 client 就断开连接了 。
除了正常情况之外,本文从 TCP 连接断开的角度结合实验给出了一些结论:
TCP 连接断开的挥手,在进程崩溃时,会由操作系统内核代劳 。
当 TCP 连接建立后,如果某一方断电或断网,如果此时刚好正在发送数据,TCP 数据包发送失败后会重试,重试达到上限时也会断开连接 。
当 TCP 连接建立后,如果某一方断电或断网,且这条连接没有数据传输时 。
如果开启了 KeepAlive 则会在一定心跳检测后断开连接,这个默认检测时间大概2个多小时,比较久 。
如果未开启 KeepAlive 则连接永远存在 。
如果一方发送 RST 包给另一方,也是会强制对方断开连接的 。
原文链接:https://mp.weixin.qq.com/s/7SvkHe3FiljxBWFkm8oAeA 。
最后此篇关于四个实验,彻底搞懂TCP连接的断开的文章就讲到这里了,如果你想了解更多关于四个实验,彻底搞懂TCP连接的断开的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在测试 SQL,但我陷入了一个查询。这是一个无用的查询,但我想理解它。 select count(*), floor(rand()*2) as x from table_name group by
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
在我编写代码时,我经常喜欢查看代码库中特定区域的工作原理或某些表达式产生的结果。 大多数其他语言都提供了在运行时评估新的自定义表达式的工具。 Golang 似乎还没有提供这个功能,或者至少没有我使用过
1、kvm 简介 kernel-based virtual machine的简称,是一个开源的系统虚拟化模块,自linux 2.6.20之后集成在linux的各个主要发行版本中。它使用linux
我是中继新手,我正在尝试在并发模式下使用中继现代实验。我已经能够使用 Suspense 和 ErrorBoundary 很好地加载节点、边等。我现在正在处理用于创建和更新对象的表单。 我无法弄清楚如何
我正在参加在线软件安全类(class)。我正在尝试使用 shellcode 进行实验。我编写了一个易受攻击的服务器、一个注入(inject)程序、一个(可能已损坏的)shellcode,我将其转换为程
我最糟糕的噩梦是日期对象,所以我创建了一个 fiddle 来查看它是如何工作的,并尝试为以下格式的 date strings 找到解决方案 2015-10- 05T11:49:13.587Z 但要注意
我一直在研究 Accessibility Object Model API,我认为尝试在 Puppeteer 测试中使用它会很酷。 getComputedAccessibleNode 返回一个 pro
我目前正在概述 C++11 的新特性,由于目前不明原因,其中一些特性无法编译。我使用 gcc version 4.6.0 20100703 (experimental) (GCC) 所以根据 GNU
1.动态年龄判定规则 对象进入老年代的4个常见的时机: 1、 躲过15次gc,达到15岁高龄之后进入老年代; 2、 动态年龄判定规则,如果Survivor区域内年龄1+年龄2+年龄3+年龄n的对象
有没有办法停止ray.tune实验(例如使用 PBT)当明显过度拟合或一个指标长时间没有改善时? 最佳答案 现在,这在 Tune 中得到了很好的支持,https://github.com/ray-pr
我尝试在gcc 6.0的开发中实际使用新的c++ 1z功能。 如果我尝试这个小例子: #include #include namespace fs = std::experimental::fil
我想知道为什么我在服务器端运行实验时必须包含 JavaScript cxApi。此外,我可以通过 PHP 发送选定的实验和变体吗?或者可能通过在没有外部资源(如 cxApi)的情况下注入(inject
我正在开发一个使用 Firebase iOS SDK 的 iOS 应用,我正在尝试弄清楚如何访问用户已看到的所有 Firebase AB 实验以及用户参与的实验变体。 我查看了文档以及 Firebas
我用 python 2.7.7 运行了以下命令: import gc import memory_profiler print memory_profiler.memory_usage()[0] x
我在浏览器控制台中做了一个 JavaScript 实验 - 首先我创建了一个新对象 foo 如下 var foo = { bar: function() { return this.baz
据说“4916 个正面训练示例经过手工挑选对齐、归一化并缩放到 24x24 的基本分辨率。通过从 9500 张不包含人脸的图像中随机挑选子窗口来选择 10,000 个负面示例。”在论文“Paul Vi
这个问题在这里已经有了答案: 关闭 12 年前。 Possible Duplicate: Can you write object oriented code in C? 嗨! 只是为了好玩,这两天
1. 程序的JVM参数示范 已知,平时系统运行创建的对象,除非是那种大对象,否则通常来说都是优先分配在新生代中的Eden区域的。 而且新生代还有另外两块Survivor区域,默认Eden区域占据新
在 上创建新实验DAGsHub 使用Git,".._metrics.csv"的格式应该是什么和 ".._params.yml"文件? 不幸的是,我在任何地方都找不到引用。 最佳答案 特尔;博士: 对于
我是一名优秀的程序员,十分优秀!