游戏服务器开发基础:TCP三次握手和四次挥手

游戏服务器的数据传输通常基于TCP协议。了解TCP连接的建立过程和释放过程,才能更好的控制网络连接、优化网络性能。

比如,清楚TCP连接释放过程,才能理解SO_REUSEADDR选项控制端口能否立刻复用的意义:这是因为主动释放TCP连接的一方会进入TIME_WAIT状态,在这个状态下,这个连接的端口是不能被复用的。但游戏服务器希望重启之后能立刻绑定这个端口,因此一般会选择启用这个选项。

TCP三次握手

TCP建立连接的图示如下:

假定主机A运行的是TCP客户程序,B运行TCP服务器程序。

最初双方都处于CLOSED(关闭)状态。一开始,B的TCP服务器进程会先创建传输控制块TCB,准备接收客户进程的连接请求。然后B就进入LISTEN(收听)状态。

A的TCP客户进程也是先创建传输控制块TCB。然后打算建立TCP连接时,向B发出TCP连接请求报文。报文首部的同步位SYN置1,同时选择一个初始序号seq=x。这时,TCP客户进程进入SYN-SEND(同步已发送)状态。

B在接收到连接请求报文后,若同意建立连接,会向A发送确认。首部的SYN和ACK置1,确认号为x+1,选择初始序号为y。这时,TCP服务器进程进入SYN-RCVD(同步收到)状态。

A收到B的确认后,还要向B发送确认。首部的ACK置1,确认号为y+1,自己的序号为x+1。这时,TCP连接已经建立,A进入ESTABLISHED(已建立连接)状态。

B收到A的确认后,也进入ESTABLISHED状态。

为什么A还要发送一次确认呢?

这是防止"已失效的TCP连接请求报文段"到了B,因而产生错误。

假设A发送了一个TCP连接请求报文段,但迟迟没有收到B的确认。那么A会再发一次TCP连接请求报文段,然后成功建立连接。数据传输完毕后,关闭了连接。

若为丢失的TCP连接请求报文报只是在某个网络结点长时间滞留了,导致在TCP连接释放后的某个时间才到达B。那么B就会以为A发起了新的TCP连接请求,并向A发送确认。

如果A不需要发送最后一次确认。那么B在发送了确认报文段后,就认为连接已经建立,并等待A发送数据。但A其实没有发送TCP连接请求报文段,就会忽略B发送的确认,也不会向B发送数据。那么,B的很多资源就这样白白浪费了。

什么是传输控制块TCB?

传输控制块(Transmission Control Block)存储了每一个连接中的一些重要信息,如:TCP连接表,指向发送和接收缓存的指针,指向重传队列的指针,当前的发送和接收序号,等等。

TCP四次挥手

TCP释放连接的图示如下:

数据传输后,连接的双方都可以释放连接。现在A和B都处于ESTABLISHED状态。

A先发送TCP连接释放报文段。首部的终止控制位置1,序号为u。这时,A进入FIN-WAIT-1(终止等待1)状态,等待B的确认。

B收到连接释放报文段后发送确认,确认号为u+1,自己的序号seq为v。然后B进入CLOSE-WAIT(关闭等待)状态。这时,A到B方向的连接就释放了,TCP连接处于半关闭(half-close)状态,即A已经没有数据要发送了,但B要发送数据,A还要接收。

A收到B的确认后,进入FIN-WAIT-2(终止等待2)状态,等待B发送连接释放报文段。

若B没有要向A发送的数据了,那么就发送TCP连接释放报文段。此时B的序号为w。B还必须重复上次已经发送过的确认号ack=u+1。这时,B进入LAST-ACK(最后确认)状态。

A在收到B的连接释放报文段后,必须对此发出确认。首部ACK置1,确认号为w+1,自己的序号为u+1。然后进入TIME-WAIT(时间等待)状态。经过时间等待计时器(TIME-WAIT timer)设置的2MSL(Maximun Segment Lifetime,最长报文段寿命)后,即经过4分钟后,A进入CLOSED。在A撤销相应的传输控制块TCB后,就结束了这次的连接。

B在收到A的确认后,就进入CLOSED。同样,B在撤销相应的传输控制块TCB后,就结束了这次的TCP连接。

为什么A在TIME-WAIT状态必须等待2MSL的时间呢?

  1. 为了保证A发送的最后一个ACK报文段能够到达B。这个ACK报文段可能会丢失,导致B接收不到对已发送的FIN+ACK报文段的确认。那么,B会超时重传这个FIN+ACK报文段,A就能在2MSL时间内收到这个重传的FIN+ACK报文段。接着,A重传一次确认,重新启动2MSL计时器。最后,A和B都能够正常释放连接。若A不在TIME-WAIT状态下等待一段时间,而是在发送ACK报文段后立刻释放连接,就无法收到B重传的FIN+ACK报文段,也不会再发送一次确认。那么,B就无法按正常步骤释放连接。
  2. 防止"已失效的TCP连接报文"出现在本连接中。A在发送完最后一个ACK报文段之后,再经过2MSL,就可以使本连接持续时间内所产生的所有报文都从网络中消失。

一些报文段的规定

  1. TCP规定,SYN报文不能携带数据,但要消耗一个序号。
  2. TCP规定,ACK报文段可以携带数据。但如果不携带数据则不消耗序号。
  3. TCP规定,FIN报文即使不携带数据,也消耗掉一个序号。
相关推荐
IT_陈寒3 小时前
闭包陷阱让我加了两天班,JavaScript你真行
前端·人工智能·后端
易协同低代码4 小时前
通达OA核心类库TD类深度解析
后端
Gopher_HBo4 小时前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志5 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..5 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects5 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰5 小时前
一些基础和问题解决
后端
陈随易6 小时前
前端项目部署只要30秒
前端·后端·程序员
YIAN6 小时前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp
Imchendiana6 小时前
《狂人日记NO.9》— 前后端一把梭,我的全栈实录
前端·后端