TCP的连接过程
在tcp协议中,主动发起连接请求的为客户端,被动连接的为服务端。初次连接有三次握手,即三个报文的交换。释放连接时有四次挥手,即4个报文的交换。 三次握手的过程。有A客户端、B服务端。B服务器进程首先创建传输模块,准备接收客户端的连接请求。这时服务端处于listen监听状态。A客户端进程先创建传输模块,然后向服务端发送连接请求报文。B服务端收到报文后如同意连接,将发送一个应答报文。客户端A收到报文后向服务端B发送一个确认报文。致此连接建立。
整个过程是怎么样的呢?
逻辑上我们可以这么理解建立链接的过程,有两台主机A和B:
- SYN:seq=X;
- A的TCP程序,为这个链接分配一个端口(设为9090)。
- 同时 逻辑上 的将TCP连接的状态设置为:正在连接。(通过在链接状态表中添加一条记录,记录中状态为:正在连接)
- 同时,随机生成一个初始序列号X,生成一个TCP包,将初始化序列号X设置为TCP中的序列号,发送给主机B。
- SYN:seq=Y ACK:ack=X+1;
- B上TCP程序收到该数据包,查询9091端口状态,如果可以链接。
- 同样的,在逻辑上的将TCP连接的状态设置为:正在连接
- 同时,随机生成一个初始化序列号Y,根据接收的序列号X,生成应答号X+1,生成一个TCP包,将序列号和应答号分别设置到TCP包头中,将TCP数据包发给主机A。
- SYN:seq=X+1 ACK:ack=Y+1.
- A上的TCP程序接收到数据包,查询9090端口状态。
- 根据收到的SYN:seq=Y;ACK:ack=X+1; 封装一个TCP包 SYN:seq=x+1;ACK:ack=Y+1;发送给主机B。同时,TCP程序将链接状态表中该条记录状态设置为已连接。
- 主机B收到数据包,TCP程序将链接状态表中该条记录状态设置为已连接。
至此,一个TCP链接建立(三次握手)完成。
我们可以看到:
- 传送的都是IP数据包,其实只是将收到的数据包交给TCP程序处理
- 链接状态,只是TCP程序中的一个逻辑状态
三次握手的目的是什么?
TCP是面向链接的,在面向链接的环境中,开始传输数据之前,在两个中端之间必须先建立一个链接。建立链接的过程可以确保通信双方在发送应用程序数据包之前,都已经准备好了传送和接收数据。并且使通信双方统一了初始化序列号。
为什么有3次握手?
- 正常情况
client发送了连接请求,但是请求报文因为种种原因丢失而未确认。于是A超时重传,再一次发送请求连接报文。server收到了,然后再发送请求确认报文,并最终完成client与server的连接。数据传输结束后,释放连接。这个过程中,client一共发送了两个请求连接报文段,第一个丢失,第二个到达server。 - 异常情况
在网络不好的情况下,client发送一个请求连接报文,然后超时没有收到服务器应答后,再次发送一个请求连接报文,这时突然关闭了连接。
然后服务器收到了请求连接的报文,发送一个应答报文后建立了连接,但因为客户端已经关闭了连接,所以肯定不会像服务器发送数据,这就导致资源被浪费了。
采用三次握手的办法可以防止上述现象发生。
四次挥手
- Client发送FIN后,进入终止等待状态,seq=m;此时Client不再像Server发送数据,比如电话的音频数据,视频会议的视频数据。
- Server收到Client连接释放报文段后,就立即给Client发送确认报文,ack=m+1;此时Server还会向Client发送数据包。
- 如果Server没有数据报发送给Client,开始第三次挥手。Server向Client发送FIN报文,seq=n;
- Client回复Server关闭请求,ack=n+1;然后客户端进入TIME_WAIT状态,此时TCP连接还没有释放。但Server收到回复后关闭连接。Client经过2MSL后依然没有收到Server的回复则证明其连接已被关闭,因此Client关闭连接。
为什么是 2MSL?
MSL是最大的报文生存时间,报文超过这个时间将被丢弃。这个是由时间等待计时器设置的。
- 理由一
- 在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。
- 理由二
- client再发送完最后一个报文端ACK之后,再经过2MSL的时间,就可以是本次连接持续时间内的所有产生的报文段都消失,这样下一次连接中就不会出现旧的请求连接报文段。
为什么是四次挥手?
因为Client发送FIN关闭报文时表示Client没有数据要向Server发送了,但Server收到FIN报文时可能还有数据没有发送完,所以只能发送一个ACK回复收到了。
等发送完数据再向Client发送FIN报文请求关闭。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)