TCP三次握手四次挥手详解

TCP 协议简介

传输控制协议(TCP,Transmission Cntrol Protocal),提高可靠的、端到端的、面相字节流的有连接传输协议。

面向有连接是指在传送数据之前必须先建立连接,数据传送完成后要释放连接;面相字节流是端到端之间不保留消息边界,例如,将 4 个 512 字节写在一个 TCP 流中,那么这些数据有可能按照4 个 512 字节、2 个 1024 字节、1 个 2048 字节或者其他方式被递交给进程,接收端是不知道这些数据被写入字节流时的单元大小,所以 TCP 不理解也不关心字节流的含义,一个字节就是一个字节

任何 TCP发送数据之前, 都必须建立一条联通两端的连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。
同时由于TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,TCP是全双工模式,所以需要四次挥手关闭连接。

TCP 服务由发送端的接收端创建一种套接字(socket)的端点来获得的,每个 socket 有一个socket 编号,由主机的 IP 和 16 位的端口组成,1024 以下的端口被保留只能由特权用户启动的标准服务,这些端口成为知名端口(well-know port)。可以在www.iana.org查询所有知名端口的列表,常见列表如下:

端口 协议 用途
20,21 FTP 文件传输
22 SSH 远程登录,Talent 的替代品
25 SMTP 电子邮件
80 HTTP 万维网
110 POP-3 访问远程邮件
143 IMAP 访问远程邮件
443 HTTPS 安全的 Web(SSL\TLS 之上的 HTTP)
543 RTSP 媒体播放控制
631 IPP 打印共享

TCP 段的头

下面是对于 TCP 头的一些解释:

  1. 源端口号,16位,发送方的端口号。
  2. 目标端口号,16位,发送方的目标端口号。
  3. 32为序列号,sequence number,字节流的序号,保证网络传输数据的顺序性。
  4. 32位确认号,acknowledgment number,用来确认确实有收到相关封包,内容表示期望收到下一个报文的序列号,用来解决丢包的问题,他是累计确认的。
  5. 头部大小,4位,偏移量:最大值为0x0F,即15;指明了包含多少个 32 位的字 ,单位为32位(bit),单位也就是4个字节,给出头部占32bit的数目。没有任何选项字段的TCP头部长度为20字节;最多可以有60(15*4)字节的TCP头部。
  6. Reserved 4位 ,预留字段,都为0
  7. TCP标志位
    1. CWR:Congestion window reduced,拥塞窗口减少。拥塞窗口减少标志被发送主机设置,用来表明它接收到了设置ECE标志的TCP包。拥塞窗口是被TCP维护的一个内部变量,用来管理发送窗口大小。
    2. ECN-Echo:显式拥塞提醒回应。当一个IP包的ECN域被路由器设置为11时,接收端而非发送端被通知路径上发生了拥塞。ECN使用TCP头部来告知发送端网络正在经历拥塞,并且告知接收端发送段已经受到了接收端发来的拥塞通告,已经降低了发送速率。
    3. URG:紧急标志位,表示数据包的紧急指针域有效,用来保证连接不被阻断,并督促中间设备尽快处理;为1时,紧急指针(urgent pointer)有效,配合紧急指针使用
    4. ACK:确认标志位,对已接收的数据包进行确认,为1时,确认号有效
    5. PSH: 推送标志位,表示该数据包被对方接收后应立即交给上层应用,而不在缓冲区排队;为1时,接收方应该尽快将这个报文段交给应用层
    6. RST:重置标志位,用于连接复位、拒绝错误和非法的数据包,为1时,释放连接,重连。
    7. SYN:同步标志位,用于建立会话连接,同步序列号,为1时,发起一个连接。
    8. FIN:完成标志位,表示我已经没有数据要发送了,即将关闭连接,为1时,关闭一个连接。
  1. 16位窗口大小:占16bit。此字段用来进行流量控制,主要用于解决流控拥塞的问题。单位为字节数,这个值是本机期望一次接收的字节数。
  2. 16位校验值: 占16bit。对整个TCP报文段,即TCP头部和TCP数据进行校验和计算,并由目标端进行验证。
  3. 16位紧急指针:占16bit。它是一个偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。
  4. 32位Tcp选项:一般包含在三次握手中,必须是 32 位的倍数。

TCP数据包由两部分组成:一部分是协议所要用到的首部,另一部分是上一层传过来的数据。首部的结构由协议的具体规范详细定义。在数据包的首部,明确标明了协议应该如何读取数据。反过来说,看到首部,也就能够了解该协议必要的信息以及所要处理的数据。

TCP 连接建立

为什么需要三次握手?

TCP需要三次握手是为了建立可靠的连接。当客户端想要和服务器建立连接时,它会发送一个SYN(同步)报文段给服务器,告诉服务器它想要建立连接。服务器收到客户端的SYN报文段后,会回复一个SYN/ACK(同步/确认)报文段给客户端,告诉客户端它已经收到了请求,并准备好建立连接。最后,客户端会发送一个ACK(确认)报文段给服务器,告诉服务器它已经收到了服务器的回复,连接建立成功。

这个过程需要三次握手是为了保证连接的可靠性。如果只有两次握手,那么就无法确定客户端是否已经收到了服务器的回复。例如,在第二次握手后,服务器可能会因为网络故障或其他原因没有收到客户端的回复,此时服务器会认为连接已经建立成功。但是客户端并没有收到服务器的回复,此时客户端会认为连接没有建立成功。如果客户端继续发送数据,那么服务器就会认为这是一条无效的连接,并拒绝接收数据。

这个过程需要三次握手是因为在网络中,每个报文段都可能会丢失、延迟或重复。如果只有两次握手,那么客户端发送的SYN报文段可能会丢失,而服务器不知道客户端想要建立连接。如果有第三次握手,那么客户端会在第三个报文段中确认服务器的回复,从而确保连接建立成功。

TCP 使用三次握手来建立连接,建立一个 TCP 连接时,需要客户端和服务器总共发送3个报文。

首先,某一端,譬如服务器必须先执行 LISTEN 和 ACCEPT 原语,然后被动等待连接请求,此时可以指定只有一个连接请求,也可以不指定。

其次,另一段(譬如客户端)执行 CONNECT原语,同时说明他希望连接的 IP 和端口号,愿意接受的最大 TCP 段长,以及一些其他参数,开始三次握手,握手示意图如下:

以客户端和服务端通信为例:

第一次握手:

TCP报文标志位SYN置为1,产生随机序号值seq=x,保存在TCP首部的序列号(Sequence Number)字段里,指明客户端打算连接的服务器的端口,并将该数据包发送给服务器端,发送完毕后,客户端进入SYN_SENT状态,等待确认。

第二次握手:

服务器端由SYN=1知道客户端请求建立连接,服务器端将TCP报文标志位SYN和ACK都置为1,ack(也就是 ack_seq,ack 的值位上一次报文的序列号 seq+1)=x+1,随机产生一个序号值seq=y,并将该数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD状态。

第三次握手:

客户端收到确认后,检查ack是否为x+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=y+1,并将该数据包发送给服务器端,服务器端检查ack是否为y+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。

注意:小写的ack代表的是头部的确认号Acknowledge number,是对上一个包的序号进行确认的号,ack=seq+1。

大写的ACK,是TCP首部中的和 SYN 一样的标志位,用于标志的TCP包是否对上一个包进行了确认操作,如果确认了,则把ACK标志位设置成1。

TCP断开连接

为什么需要四次挥手

TCP连接是全双工的,但是为例方便理解,我们可以把他想象成是一对单工连接,每个单工连接彼此独立释放,也就是说,每个方向都可以去发送 FIN 的 TCP 标志位,这表示他已经没有数据需要发送了,当另一个方向确认后,这个方向上的连接就被关闭了,不再发送任何数据。注意, 当一个方向上的数据被关闭后,另一个方向上可能还存在着无线的数据流,当两个方向上都被关闭后,连接才算彻底释放。

通常情况下,释放一个链接需要四个TCP端:每个方向上一个FIN和一个ACK,然而,第一个ACK和第二个FIN有可能被组合到同一个段中,从而将所需要的段降低到三个

四次挥手

我们这里以客户端发起挥手为例,实际也可能是服务端等发起

第一次挥手:

客户端发起挥手请求,此时客户端(发起端)已经没有数据需要发送给服务端了(服务端可能还在发送数据),向服务端发送标志位是FIN=1报文段,设置随机序列号seq=u,此时,客户端进入FIN_WAIT_1等待状态。

第二次挥手:

服务端收到了客户端发送的FIN报文段,向客户端返回一个标志位是ACK的报文段,b表达接受到了并返回确认,ack=seq+1,客户端进入FIN_WAIT_2状态,服务端告诉客户端,我确认并同意你的关闭请求。

第三次挥手:

服务端向客户端发送标志位是FIN的报文段,请求关闭连接,同时服务端进入LAST_ACK状态。

第四次挥手:

客户端收到服务端发送的FIN报文段,向服务端发送标志位是ACK的报文段,然后客户端进入TIME_WAIT状态。服务端收到客户端的ACK报文段以后,就关闭连接。此时,客户端等待2MSL的时间后依然没有收到回复,则证明服务端已正常关闭,那好,客户端也可以关闭连接了。

一个TCP连接的两端也可能会同时发送FIN段,这两个段按常规方法被单独确认,然后关闭连接,实际上,两台主机可以先后释放连接或同时释放连接,这两者之间并无本质区别。

同时,如果在两倍的最大数据包生存期。针对FIN的响应没有出现,将直接释放连接

为什么要等待2MSL(两倍的最大数据包生存期)?

MSL:报文段最大生存时间,它是任何报文段被丢弃前在网络内的最长时间。
有以下两个原因:

  • 第一点:保证TCP协议的全双工连接能够可靠关闭
    由于IP协议的不可靠性或者是其它网络原因,导致了服务端没有收到客户端的ACK报文,那么服务端就会在超时之后重新发送FIN,如果此时客户端的连接已经关闭处于CLOESD状态,那么重发的FIN就找不到对应的连接了,从而导致连接错乱,所以,客户端发送完最后的ACK不能直接进入CLOSED状态,而要保持TIME_WAIT,当再次收到FIN的收,能够保证对方收到ACK,最后正确关闭连接。
  • 第二点:保证这次连接的重复数据段从网络中消失
    如果客户端发送最后的ACK直接进入CLOSED状态,然后又再向服务端发起一个新连接,这时不能保证新连接的与刚关闭的连接的端口号是不同的,也就是新连接和老连接的端口号可能一样了,那么就可能出现问题:如果前一次的连接某些数据滞留在网络中,这些延迟数据在建立新连接后到达客户端,由于新老连接的端口号和IP都一样,TCP协议就认为延迟数据是属于新连接的,新连接就会接收到脏数据,这样就会导致数据包混乱。所以TCP连接需要在TIME_WAIT状态等待2倍MSL,才能保证本次连接的所有数据在网络中消失。

TCP连接管理模型

image.png

参考链接

juejin.cn/post/684490…

www.cnblogs.com/bruce1992/p…

计算机网络[第五版]

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYKsgNOE' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片