游戏服务器开发基础: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报文即使不携带数据,也消耗掉一个序号。
相关推荐
Novproxy_Z15 小时前
商用代理避坑:如何识别商家拿机房 IP 冒充住宅 IP
java·网络·tcp/ip
垆边人似月.15 小时前
RDMA 文件传输踩坑(五):READY 发送成功后,为什么出现 Work Request Flushed Error?
服务器·网络·tcp/ip
深蓝AI15 小时前
Python 3.13 的 Queue.shutdown:异步消费者终于能正常收工了
后端
qetfw16 小时前
UOS DHCP Relay:跨网段分配与 IP、DNS、网关验证
linux·服务器·网络·tcp/ip·uos
尹人入圣16 小时前
目前热门的IP驱动产业新场景新工具
网络·python·网络协议·tcp/ip
武子康16 小时前
MultiNet6 空闲崩溃:`EXCVADDR=0x8` 后又出现 `CORRUPT HEAP`
人工智能·后端·agent
武子康17 小时前
MultiNet7 每轮都 clean,ESP32-P4 内存为什么还在掉?
人工智能·后端·agent
超级架构师18 小时前
PRAXO-CORE 2.5.0:用 conformance 和显式边界构建 Go Agent 框架
开发语言·人工智能·后端·golang·ai编程·智能体框架·praxo-core
叼烟扛炮18 小时前
Linux 学习笔记(四十一):TCP 并发演进——从单进程到多线程服务器
linux·运维·服务器·网络·笔记·学习·tcp/ip
陈随易18 小时前
AI 运维服务器,安全又可靠的方法
前端·后端·程序员