<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Tcp/Ip on Coder_Studio</title>
        <link>https://iamxurulin.github.io/tags/tcp/ip/</link>
        <description>Recent content in Tcp/Ip on Coder_Studio</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <copyright>iamxurulin</copyright>
        <lastBuildDate>Sun, 23 Aug 2026 17:21:42 +0000</lastBuildDate><atom:link href="https://iamxurulin.github.io/tags/tcp/ip/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>一文吃透TCP三次握手与四次挥手</title>
        <link>https://iamxurulin.github.io/p/%E4%B8%80%E6%96%87%E5%90%83%E9%80%8Ftcp%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B%E4%B8%8E%E5%9B%9B%E6%AC%A1%E6%8C%A5%E6%89%8B/</link>
        <pubDate>Fri, 10 Apr 2026 20:10:09 +0000</pubDate>
        
        <guid>https://iamxurulin.github.io/p/%E4%B8%80%E6%96%87%E5%90%83%E9%80%8Ftcp%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B%E4%B8%8E%E5%9B%9B%E6%AC%A1%E6%8C%A5%E6%89%8B/</guid>
        <description>&lt;p&gt;TCP的三次握手和四次挥手，说实话，即使背了很多很多遍，还是容易搞忘。&lt;/p&gt;
&lt;p&gt;本文，就用最直白的话梳理一下，强化记忆。&lt;/p&gt;
&lt;p&gt;首先，TCP是面向连接、保证可靠的传输层协议，和“发出去就不管”的UDP完全不一样。&lt;/p&gt;
&lt;p&gt;所以，它在正式传数据前，必须先建立可靠的连接，这就是&lt;strong&gt;三次握手&lt;/strong&gt;；&lt;/p&gt;
&lt;p&gt;数据传完要安全断开、不能丢数据，这就是&lt;strong&gt;四次挥手&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;三次握手&#34;&gt;三次握手
&lt;/h2&gt;&lt;p&gt;TCP 三次握手的目标，是让客户端与服务端互相确认双方的收发能力正常、同步双方的初始化序列号，最终建立一条可靠的 TCP 连接。&lt;/p&gt;
&lt;h3 id=&#34;第一次握手&#34;&gt;第一次握手
&lt;/h3&gt;&lt;p&gt;客户端向服务端发送一个 同步标志位（SYN=1）的同步报文，报文中携带了自己随机生成的初始化序列号。&lt;/p&gt;
&lt;p&gt;发送完成后，客户端进入&lt;strong&gt;同步已发送&lt;/strong&gt;（SYN_SENT）状态。&lt;/p&gt;
&lt;h3 id=&#34;第二次握手&#34;&gt;第二次握手
&lt;/h3&gt;&lt;p&gt;服务端收到客户端的同步请求后，会回复一个&lt;strong&gt;同步标志位&lt;/strong&gt;（SYN=1）和&lt;strong&gt;确认标志位&lt;/strong&gt;（ACK=1）都置1的同步确认报文。&lt;/p&gt;
&lt;p&gt;这个报文里，确认号是客户端的初始化序列号 + 1，同时也会携带服务端自己随机生成的初始化序列号。&lt;/p&gt;
&lt;p&gt;发送完成后，服务端进入&lt;strong&gt;同步已收到&lt;/strong&gt;（SYN_RCVD）状态。&lt;/p&gt;
&lt;h3 id=&#34;第三次握手&#34;&gt;第三次握手
&lt;/h3&gt;&lt;p&gt;客户端收到服务端的同步确认报文后，会回复一个&lt;strong&gt;确认标志位&lt;/strong&gt;（ACK=1）的确认报文，其中确认号是服务端的初始化序列号 + 1。&lt;/p&gt;
&lt;p&gt;发送完成后，客户端直接进入&lt;strong&gt;连接已建立&lt;/strong&gt;（ESTABLISHED）状态；&lt;/p&gt;
&lt;p&gt;服务端收到这个确认报文后，也会同步进入&lt;strong&gt;连接已建立&lt;/strong&gt;状态。&lt;/p&gt;
&lt;p&gt;到这里，TCP连接就正式建立完成，双方可以开始正常传输业务数据了。&lt;/p&gt;
&lt;h3 id=&#34;为什么是三次握手不是两次&#34;&gt;为什么是三次握手，不是两次？
&lt;/h3&gt;&lt;p&gt;两次握手只能保证客户端确认服务端的收发能力正常，服务端却没法确认客户端的接收能力是正常的。&lt;/p&gt;
&lt;p&gt;官话那么多，举个例子好理解一点：&lt;/p&gt;
&lt;p&gt;如果客户端发的&lt;strong&gt;同步标志位&lt;/strong&gt;（SYN=1）报文在网络里滞留了，客户端自己都放弃了，但是，这个报文在滞留结束后，还是来到了服务端。&lt;/p&gt;
&lt;p&gt;这种情况，如果是两次握手，服务端收到后就会直接建立连接，一直等着客户端发数据，但是，客户端根本就不认这个连接，也不会发数据，这样就白白浪费了服务端的资源。&lt;/p&gt;
&lt;p&gt;而如果是三次握手，服务端收到滞留的SYN报文、回复SYN+ACK后，客户端根本不会回复第三次ACK，服务端收不到最终确认，就不会建立无效连接，完美规避了资源浪费的问题。&lt;/p&gt;
&lt;h2 id=&#34;四次挥手&#34;&gt;四次挥手
&lt;/h2&gt;&lt;p&gt;四次挥手的本质，是TCP&lt;strong&gt;全双工连接&lt;/strong&gt;的&lt;strong&gt;双向关闭&lt;/strong&gt;过程。&lt;/p&gt;
&lt;p&gt;因为TCP连接是全双工的，双方都能独立发送和接收数据，所以，断开的时候，必须保证双方的数据都完全传输完毕后，再安全断开连接，不能单方面说断就断。&lt;/p&gt;
&lt;h3 id=&#34;第一次挥手&#34;&gt;第一次挥手
&lt;/h3&gt;&lt;p&gt;客户端发送一个&lt;strong&gt;结束标志位&lt;/strong&gt;（FIN=1）的结束包，告诉服务端：&lt;/p&gt;
&lt;p&gt;我的业务数据已经全部发完了，之后不会再发送数据了。&lt;/p&gt;
&lt;p&gt;发送完成后，客户端进入&lt;strong&gt;结束等待1&lt;/strong&gt;（FIN_WAIT_1）状态。&lt;/p&gt;
&lt;h3 id=&#34;第二次挥手&#34;&gt;第二次挥手
&lt;/h3&gt;&lt;p&gt;服务端收到客户端的结束包后，立刻回复一个&lt;strong&gt;确认标志位&lt;/strong&gt;（ACK=1）的确认包，其中确认号是客户端 FIN 报文的序列号 + 1。&lt;/p&gt;
&lt;p&gt;发送完成后，服务端进入&lt;strong&gt;关闭等待&lt;/strong&gt;（CLOSE_WAIT）&lt;strong&gt;状态；&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;客户端收到这个确认包后，就会进入&lt;strong&gt;结束等待2&lt;/strong&gt;（FIN_WAIT_2）状态。&lt;/p&gt;
&lt;p&gt;这里要注意：&lt;/p&gt;
&lt;p&gt;这个阶段，客户端已经不会再发送数据了，但服务端如果还有没发完的业务数据，依然可以正常给客户端发送，客户端也会正常接收。&lt;/p&gt;
&lt;h3 id=&#34;第三次挥手&#34;&gt;第三次挥手
&lt;/h3&gt;&lt;p&gt;等服务端把所有剩余的数据都发送完毕后，也会给客户端发送一个&lt;strong&gt;结束标志位&lt;/strong&gt;（FIN=1）的结束包，告诉客户端：我的数据也全部发完了，之后也不会再发送数据了。&lt;br&gt;
发送完成后，服务端进入&lt;strong&gt;最后确认&lt;/strong&gt;（LAST_ACK）&lt;strong&gt;状态&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;第四次挥手&#34;&gt;第四次挥手
&lt;/h3&gt;&lt;p&gt;客户端收到服务端的结束包后，立刻回复一个&lt;strong&gt;确认标志位&lt;/strong&gt;（ACK=1）的确认包，其中确认号是服务端FIN报文的序列号 + 1。&lt;/p&gt;
&lt;p&gt;发送完成后，客户端进入&lt;strong&gt;时间等待&lt;/strong&gt;（TIME_WAIT）状态，等待2MSL（最长报文寿命）的时间后，才会正式关闭连接；&lt;/p&gt;
&lt;p&gt;而服务端只要收到这个确认包，就会直接关闭连接。&lt;/p&gt;
&lt;p&gt;到这里，整个TCP连接就正式断开了。&lt;/p&gt;
&lt;h3 id=&#34;为什么握手只要三次挥手却要四次&#34;&gt;为什么握手只要三次，挥手却要四次？
&lt;/h3&gt;&lt;p&gt;握手的时候，服务端的SYN（同步报文）和ACK（确认报文）可以合并在同一个包里发送，所以三次就够了；&lt;/p&gt;
&lt;p&gt;但挥手的时候，服务端收到客户端的结束报文时，可能还有没发完的数据要继续传，所以只能先回复确认报文进行确认，等数据全部发完了，才能再发结束报文告诉客户端自己也可以关了。&lt;/p&gt;
&lt;p&gt;ACK和FIN分开发送，自然就变成了四次。&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
