引言
TCP 三次握手和四次挥手不管是在开发还是面试中都是一个非常重要的知识点,它是我们优化 web 程序性能的基础。但是大部分教材都对这部分解释的比较抽象,本文我们就利用 wireshark 来抓包以真正体会整个流程的细节。
三次握手
根据下面这幅图我们来看一下 TCP 三次握手。p.s: 每个箭头代表一次握手。

第一次握手
client 发送一个SYN(J)包给 server,然后等待 server 的 ACK 回复,进入SYN-SENT
状态。p.s: SYN 为 synchronize 的缩写,ACK 为 acknowledgment 的缩写。
第二次握手
server 接收到 SYN(seq=J)包后就返回一个ACK(J+1)包以及一个自己的**SYN(K)**包,然后等待 client 的 ACK 回复,server 进入SYN-RECIVED
状态。
第三次握手
client 接收到 server 发回的 ACK(J+1)包后,进入ESTABLISHED
状态。然后根据 server 发来的 SYN(K)包,返回给等待中的 server 一个ACK(K+1)包。等待中的 server 收到 ACK 回复,也把自己的状态设置为ESTABLISHED
。到此 TCP 三次握手完成,client 与 server 可以正常进行通信了。
为什么要进行三次握手
我们来看一下为什么需要进行三次握手,两次握手难道不行么?这里我们用一个生活中的具体例子来解释就很好理解了。我们可以将三次握手中的客户端和服务器之间的握手过程比喻成 A 和 B 通信的过程:
- 在第一次通信过程中,A 向 B 发送信息之后,B 收到信息后可以确认自己的收信能力和 A 的发信能力没有问题。
- 在第二次通信中,B 向 A 发送信息之后,A 可以确认自己的发信能力和 B 的收信能力没有问题,但是 B 不知道自己的发信能力到底如何,所以就需要第三次通信。
- 在第三次通信中,A 向 B 发送信息之后,B 就可以确认自己的发信能力没有问题。
wireshark
上面分析还不够形象,很容易忘记,下面我们利用 wireshark 来证明一下上面的分析过程。从下面的的输出就可以很容易看出来,必须要经过前面的三次 tcp 请求才会有起一次 http 请求。
第一次请求客户端发送一个 SYN 包,序列号是 0。

第二次请求服务器会发送一个 SYN 和一个 ACK 包,序列号是 0,ack 号是 1。

第三次本地客户端请求会发送一个 ACK 包,序列号是 1,ack 号是 1 来回复服务器。

四次挥手
以下面这张图为例,我们来分析一下 TCP 四次挥手的过程。

第一次挥手
client 发送一个FIN(M)包,此时 client 进入FIN-WAIT-1
状态,这表明 client 已经没有数据要发送了。
第二次挥手
server 收到了 client 发来的 FIN(M)包后,向 client 发回一个ACK(M+1)包,此时 server 进入CLOSE-WAIT
状态,client 进入FIN-WAIT-2
状态。
第三次挥手
server 向 client 发送FIN(N)包,请求关闭连接,同时 server 进入LAST-ACK
状态。
第四次挥手
client 收到 server 发送的 FIN(N)包,进入TIME-WAIT
状态。向 server 发送**ACK(N+1)**包,server 收到 client 的 ACK(N+1)包以后,进入CLOSE
状态; client 等待一段时间还没有得到回复后判断 server 已正式关闭,进入CLOSE
状态。
References
TCP-CONNECTION
TCP-TERMINATION
公众号
欢迎大家关注我的公众号ziwenxie_mj
订阅我博客上的原创文章 :)

p.s: 如有错误,还望指正 :)
LZ 放心。在公众号写技术文章没人看的。
写鸡汤?
每次握手,回首出现了问题会怎样
"为什么要进行三次握手" 这个问题回答到并不好 我只能给 4/10 分
三次握手其中一个功能是防 DDOS,先领会到这里能拿及格分
还以为是来讲笑话的
以第三次客户端没有发送给服务器 ack 请求为例子,这里涉及到超时和重传机制,这个时候服务器没法进入 ESTABLISHED 状态,如果超过一定时间服务器后向客户端发送 RTS 报文,同时进入 CLOSED 状态。深入一点也可以去了解一下 syn 攻击之类的 :)
完全没有在微信里看文章的癖好~
没人会在公众号看技术文章的,据我观察在朋友圈转发技术文章的,都是没有女朋友的。
MARK
还行,只要文章好还是有人看的,我就关注了 CloudMan,写的关于云和容器的东西还不错,每天 5 分钟。。
如何防 ddos,期待展开
ddos 实际上 根本防不了,链路层上 就打垮你了
指出的 syn 攻击就是利用三次握手机制 不知到是怎么防止 ddos ?
Mark
不该 mark 的,直接收藏了。
期待前排大佬能把争论的地方讲具体、讲清晰一点
建立连接三次握手,常见的有一个 SYN 攻击。
在三次握手的过程中,server 端会维护一个队列,这个队列中都是 已经向 client 返回 ACK,并等待 client ACK 的请求。
如果 client 在此时恶意的不发送 ACK,而是不停的发送 SYN,
就会导致 SERVER 端 的队列被占满,无法接受正常的 TCP 三次握手请求。
TIME_WAIT 状态是怎样产生的,为什么要这样做?
多谢科普
为什么要把教科书搬到微信公众号上。。
The client waits for a period of time equal to double the maximum segment life (MSL) time,
to ensure the ACK it sent was received.那什么是 tcp 流
感觉在握手时候应该强调下序列号同步的功能
看了评论舒了一口气
另外楼主这算是翻车么
老实说,这些贴图质量实在是太土了。下面的 Wireshark 的部分跟本就看不清。
做推广能不能有点诚意。
补充一个[wireshark 网络分析]( https://book.douban.com/subject/26268767/),考虑到了 tcp 四次挥手中的 sack 导致的 seq 不一致问题
好 我来提个问
不小心发出去了。 接上面
HTTP 协议的无状态和 keep alive 的关系是什么
把时序图 和各个状态放出来吧
恩,看着关注了一大堆公众号,不过基本上不会去看。为什么对封闭的微信热情这么高,开放的 Web 不是更好!?感谢楼主科普
值得看 谢谢
建议多看书。
作为一个 web 开发,平时都是用 http 协议,到底什么情况才需要深入到 tcp/ip 啊??
"TCP 三次握手和四次挥手不管是在开发还是面试中都是一个非常重要的知识点,它是我们优化 web 程序性能的基础"
求问如何使用这些知识来优化 web 程序?
三次握手的作用、带来的问题、问题的解决方案、解决方案仍然存在的问题,全部都在
https://tools.ietf.org/html/rfc7413 里面,讲得很清楚。而且 7413 比 793 短得多,很容易读完
我老师经常转,孩子都几个他
因为网络的不可靠性,在客户端发送了 ack 包之后,还需要等待 2ms 才到 closed 状态,因为 ack 包可能丢失,对方会重传 FIN 包,这时候客户端需要重传
三次握手给 DDoS 提供了机会,并不是用来防 DDoS 的。
还是喜欢这个版本:
你瞅啥
瞅你咋滴
呦,咋俩唠唠
萌新 请教。
在第二次通信中,B 向 A 发送信息之后,A 可以确认自己的发信能力和 B 的收信能力没有问题,但是 B 不知道自己的发信能力到底如何,所以就需要第三次通信。
B 向 A 发信息 为什么是确认 A 的发信能力。
上一个问题问的犹如智障 ,请无视。
无状态和 keep-alive 其实没有关系,是从两个角度上描述的。
无状态,意思是 HTTP 协议 的前后两次请求,是相互无关的,本次的 HTTP 请求,对上一次的 HTTP 请求没有影响,对下一次的请求没有影响。
keep-alive 可以从 TCP 的长连接,还是短连接 来说。
在 HTTP 早先的版本,默认是 一次 HTTP 请求、响应完成,就断开连接。这就是短连接。
后续因为 server、client 的性能都更好,所以就希望能够长连接,来减少 TCP 建立连接的消耗,所以后面希望推动长连接。
但为了兼容以前短连接的历史原因,如果需要长连接,请明确声明 Keep-alive。
对于这个的理解,不能站在上帝视角来看,你应该单纯的站在 A 的角度来看。
比如,你就是 A,你给 B 写信,你把信投入了邮筒之后,你怎么确定的知道你的信件送达到了 B ?
就是 B 给你回信,而且内容 与 你寄出去的那一封是相关的。
你这个时候,才能确认 你的信 之前确实到达了 B。
http://vcpu.me/TIME_WAIT%E7%8A%B6%E6%80%81%E5%88%86%E6%9E%90/ 这个对 TIME_WAIT 解释的很好,可以看下
本质山应该是为了在不可靠的网络上建立可靠的传输通道,三次刚好是一个比较稳妥的