TCP三次握手与四次挥手:工程师必备的底层原理详解

开篇暴击(建议收藏!)

各位老铁们!今天咱们要聊的这个知识点堪称程序员界的"驾照理论考试必考题"!不管是后端开发、网络运维还是安全攻防,只要你的工作要和网络打交道,TCP的三次握手与四次挥手绝对是你必须吃透的底层原理!(面试被问到的概率高达99.9%!)

先来点前菜(基础不牢地动山摇)

想象一下你在网购时疯狂点击"立即购买"按钮的场景——你每一次点击的背后,其实都是浏览器和服务器在进行复杂的"暗号对接"。这个对接过程用专业术语说就是TCP连接建立与断开,也就是咱们今天的主角:三次握手(建立连接)和四次挥手(断开连接)。

关键术语速记(重点标红!)

  • SYN:我要和你搞对象(同步序列编号)
  • ACK:我同意搞对象(确认应答)
  • FIN:咱们分手吧(结束连接)
  • SEQ:咱们的聊天暗号(序列号)
  • MSL:分手冷静期(最大分段生存时间)

正片开始:三次握手的爱情故事

第一幕:客户端发起求爱(SYN=1)

当你的浏览器(客户端)想和淘宝服务器(服务端)建立连接时,会先发个"求爱信号":

SYN=1, seq=x

(这个x就像初次见面的自我介绍暗号)

第二幕:服务器的双向确认(SYN+ACK)

服务器收到求爱信号后,会给出双重回应:

SYN=1, ACK=1, seq=y, ack=x+1

(y是服务器的自我介绍暗号,x+1表示"我记住你的暗号了")

第三幕:最后的确认(ACK)

客户端收到回应后必须再确认一次:

ACK=1, seq=x+1, ack=y+1

(这里如果客户端不回应,服务器会像等不到回应的舔狗一样持续发送确认请求)

灵魂拷问:为什么非要三次?

很多萌新会问:两次确认不行吗?想象这个场景:

  1. 客户端发送SYN(信号1)
  2. 信号1卡在路由器里
  3. 客户端重发SYN(信号2)
  4. 服务器响应信号2建立连接
  5. 此时卡住的信号1突然到达服务器…
    (恭喜你收获了一个僵尸连接!)

分手大戏:四次挥手的哲学

第一幕:客户端提分手(FIN=1)

当数据传输完毕,客户端会发送:

FIN=1, seq=u

(此时进入FIN-WAIT-1状态,就像说"我想分手"但还没正式分)

第二幕:服务器的及时回应(ACK)

服务器立即回应:

ACK=1, seq=v, ack=u+1

(进入CLOSE-WAIT状态,相当于说"我知道了"但自己可能还有话要说)

第三幕:服务器的最后告白(FIN)

当服务器处理完所有数据,才会发送:

FIN=1, ACK=1, seq=w, ack=u+1

(进入LAST-ACK状态,相当于"我也准备好了")

第四幕:客户端的最终确认(ACK)

客户端必须再发一次确认:

ACK=1, seq=u+1, ack=w+1

(进入TIME-WAIT状态,要等2MSL才彻底关闭)

死亡问答:为什么分手比牵手多一步?

因为TCP连接是全双工的!就像情侣分手:

  • 你说要分手(FIN)
  • 对方说知道了(ACK)
  • 对方可能还有话说(数据传输)
  • 对方也说要分手(FIN)
  • 你最后确认(ACK)

实战踩坑记录(血泪教训!)

场景1:线上服务TIME_WAIT堆积

某次大促时我们的Nginx服务器出现大量TIME_WAIT连接,直接导致新连接无法建立。解决方案:

# 调整内核参数
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1

(注意:这两个参数在NAT环境下可能有副作用!)

场景2:惊群效应导致握手失败

早期版本Tomcat的BIO模型在应对高并发连接时,三次握手的ACK包可能被多个线程争抢,解决方案:

// 使用NIO模型+多路复用器
ServerSocketChannel serverChannel = ServerSocketChannel.open();
Selector selector = Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);

高级玩家必备(面试加分期)

Q:SYN洪水攻击原理?

攻击者伪造大量SYN包但不完成握手,耗尽服务器资源。防御方案:

  • SYN Cookie技术
  • 限制半开连接数

Q:TIME_WAIT为什么是2MSL?

  1. 确保最后一个ACK能到达
  2. 让本连接持续时间内产生的所有报文都从网络中消失

Q:CLOSE_WAIT状态堆积怎么办?

大概率是代码bug!检查是否忘记关闭socket:

# 错误示范
s = socket.socket()
s.connect(...)
# 忘记s.close()

# 正确做法
with socket.socket() as s:
    s.connect(...)

抓包实战演示(Wireshark警告!)

当我们用Wireshark抓取一个HTTP请求时:

  1. 过滤器输入tcp.port == 80
  2. 找到三次握手的三次TCP报文
  3. 观察Flags字段的SYN/ACK变化
  4. 四次挥手同理(注意FIN标志位)

(小技巧:右键任意TCP包 -> Follow -> TCP Stream 可以直观看到完整会话)

终极总结(建议刻进DNA)

三次握手和四次挥手就像程序员的网络礼仪:

  • 建立连接要谨慎(三次确认防错乱)
  • 断开连接要体面(四次告别保周全)
  • 状态转换要记牢(八种状态如数家珍)
  • 参数调优要慎重(内核参数别乱改)

下次当你curl一个接口或者axios.get()一个API时,不妨在脑海里过一遍这些底层交互——这不仅是面试装逼的资本,更是定位网络问题的核武器!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值