- 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的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我是 ZMQ 的新手。我发现 ZMQ 套接字实现比 winsock 简单得多。但我怀疑 “使用 ZMQ TCP 套接字创建的客户端可以与传统的 TCP 服务器通信吗?” 换句话说我的 ZMQ 客户端可
我想使用 TCP 协议(protocol) 将数据发送到 Logstash。为了发送数据,我正在使用 Node-RED。一个简单的配置如下所示: 在 Logstash 文件夹中,我创建了一个名为 no
当我尝试更改窗口缩放选项时,作为 root,我可以通过在 /proc/sys/net/中执行 net.ipv4.tcp_mem=16777000 来更改值。如果我必须更改这 100 个系统,那将需要大
明天做一些练习题,这道做不出来 TCP 服务器连接 TCP 客户端进行通信所需的最小套接字端口数是多少? 肯定只有两个吧?一个用于服务器,一个用于客户端,但这似乎是显而易见的。我的伙伴们认为 TCP
考虑一个存在一个服务器和多个客户端的场景。每个客户端创建 TCP 连接以与服务器交互。 TCP alive的三种用法: 服务器端保活:服务器发送 TCP 保活以确保客户端处于事件状态。如果客户端死了,
TCP TAHOE 和 TCP RENO 有什么区别。 我想知道的是关于 3-dup-ack 和超时的行为? SST 发生了什么变化? 谢谢! 最佳答案 TCP Tahoe 和 Reno 是处理 TC
大家早上好。我一直在阅读(其中大部分在堆栈溢出中)关于如何进行安全密码身份验证(散列 n 次,使用盐等)但我怀疑我将如何在我的 TCP 客户端中实际实现它-服务器架构。 我已经实现并测试了我需要的方法
在遍历 RFC793 时,我开始知道应该以这种方式选择初始序列号段重叠被阻止。 有人能解释一下如果发生重叠,重复段将如何影响 TCP? 最佳答案 不同的操作系统有不同的行为。参见 http://ins
你能举例说明一下tcp/ip中nagle算法的概念吗? 最佳答案 我认为Wikipedia在开头的段落中做得很好。 Nagle's document, Congestion Control in IP
似乎最大 TCP 接收窗口大小为 1GB(使用缩放时)。因此,仍然可以用一个连接填充 100Gb 管道的最大 RTT 是 40ms(因为 2 * 40E-3 * 100E9/8 = 1GB)。这会将这
考虑在两个 TCP 端点之间建立的 TCP 连接,其中一个调用: 关闭():此处,不允许进一步读取或写入。 关机(fd,SHUT_WR):这会将全双工连接转换为单工连接,其中调用 SHUT_WR 的端
我是在 Lua 中编写解析器的新手,我有两个简短的问题。我有一个包含 TCP 选项的数据包,如 MSS、TCP SACK、时间戳、NOP、窗口比例、未知。我基本上是在尝试剖析 TCP 选项字段中的未知
TCP 是否不负责通过在传输过程中发生丢失等情况时采取任何可能必要的措施来确保通过网络完整地发送流? 它做的不对吗? 为什么更高的应用层协议(protocol)及其应用程序仍然执行校验和? 最佳答案
考虑使用 10 Mbps 链路的单个 TCP (Reno) 连接。假设此链路不缓冲数据并且接收方的接收缓冲区比拥塞窗口大得多。设每个 TCP 段的大小为 1500 字节,发送方和接收方之间连接的双向传
考虑这样一个场景,有client-a和server-b。 server-b 禁用了 TCP keepalive。 server-b 没有任何应用程序逻辑来检查 TCP 连接是否打开。 client-a
我正在尝试用 Rust 编写回显服务器。 use std::net::{TcpStream, TcpListener}; use std::io::prelude::*; fn main() {
听说对于TCP连接,服务器会监听一个端口,并使用另一个端口发送数据。 例如,Web 服务器监听端口 80。每当客户端连接到它时,该服务器将使用另一个端口(比如 9999)向客户端发送数据(Web 内容
我试图了解带有标记 PSH 和标记 URG 的 TCP 段之间的区别。我阅读了 RFC,但仍然无法理解,其中一个在将数据发送到进程之前缓冲数据而另一个没有吗? 最佳答案 它们是两种截然不同的机制。 #
有第三方服务公开 TCP 服务器,我的 Node 服务器(TCP 客户端)应使用 tls Node 模块与其建立 TCP 连接。作为 TCP 客户端, Node 服务器同时也是 HTTP 服务器,它应
我正在发送一些 TCP SYN 数据包以获得 TCP RST 的返回。为了识别每个探测器,我在 TCP 序列字段中包含一个计数器。我注意到以下几点: 当SYN probe中的sequence numb
我是一名优秀的程序员,十分优秀!