【计算机网络】TCP协议中三次握手和四次挥手过程

一、TCP 基本认识

1、TCP 头格式(报文格式)

在这里插入图片描述
(1)序列号(sequence number):Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记,在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,用来解决网络包乱序问题。
(2)确认应答号(acknowledgement):Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,发送端收到这个确认应答以后认为在这个序号以前的数据都已经被正常接收。用来解决不丢包的问题,Ack=Seq+1。
(3)控制位(标志位):

URG:紧急指针
ACK:确认序号字段有效,该位设置为 1
PSH:接受方应该尽快将这个报文交给应用层
RST: TCP 连接中出现异常时重置连接
SYN:建立连接,发起一个连接
FIN:断开连接,释放一个连接

注意:不要将确认序号Ack和标志位中的ACK搞混了,确认方Ack=发起方Seq+1,而标志位中的ACK通常设置为1。

2、什么是 TCP ?

TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。
(1)面向连接:一对一连接,一个主机同一时间只能向一个主机发送消息;
(2)可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端
(3)字节流:消息是没有边界的,所以无论消息多大都可以进行传输。并且消息是有序的,当前一个消息没有收到的时候,即使它先收到了后面的字节已经收到,那么也不能交给应用层去处理,同时对重复的报文会自动丢弃。

3、为什么需要 TCP 协议?

TCP 是一个工作在传输层的可靠数据传输控制协议,处于IP层(网络层)的上层(传输层),它能保障网络数据包的可靠性,确保接收端接收的网络包是无损坏、无间隔、非冗余和按序的。而IP 层是不可靠的,它不保证网络包的交付、不保证网络包的按序交付、也不保证网络包中的数据的完整性。

4、UDP 和 TCP的区别及应用场景

在这里插入图片描述

(1)UDP头部格式:

在这里插入图片描述

目标和源端口:主要是告诉 UDP 协议应该把报文发给哪个进程。
包长度:该字段保存了 UDP 首部的长度跟数据的长度之和。
校验和:校验和是为了提供可靠的 UDP 首部和数据而设计。

(2)UDP 和 TCP的区别:

  • 连接

TCP 是面向连接的传输层协议,传输数据前先要建立连接;
UDP 不需要连接,即刻传输数据;

  • 服务对象

TCP 面向字节流,一对一的两点服务,即一条连接只有两个端点;
UDP 面向报文的,支持一对一、一对多、多对多的交互通信;

  • 可靠性

TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按需到达;
UDP 是尽最大努力交付,不保证可靠交付数据;

  • 传输速率

TCP 有拥塞控制和流量控制机制,保证数据传输的安全性,传输速率比UDP慢;
UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率(对实时应用很有用,如IP电话,实时视频会议等);

  • 首部开销

TCP 头部有「首部长度」字段,TCP 首部长度较长,首部开销20字节;
UDP 头部没有「首部长度」字段,UDP 首部只有 8 个字节,并且是固定不变的,开销较小,无需多一个字段去记录 UDP 的首部长度;

  • 其他

TCP对系统资源要求较多,而UDP较少;
TCP比UDP复杂,UDP程序结构较简单;

(3)UDP 和 TCP的相似点:

都是传输层协议,负责不同主机中进程间通信。

(4)UDP 和 TCP的应用场景:

  • TCP 是面向连接,能保证数据的可靠性传输,应用于文件传输,重要状态更新等场景:

FTP 文件传输
HTTP / HTTPS
SSH、FTP
TELNET
SMTP(简单邮件传输协议)

  • UDP 面向无连接,它可以随时发送数据,本身的处理既简单又高效,用于对高速传输和实时性要求较高的通信领域:

包总量较少的通信,如 DNS 、SNMP(简单网络管理协议) 等
视频、音频等多媒体通信
广播通信
TFTP、DHCP等

5、TCP连接

(1)用于保证可靠性和流量控制维护的某些状态信息,包括Socket、序列号和窗口大小,这些信息的组合称为连接。建立一个 TCP 连接是需要客户端与服务器端达成上述三个信息的共识。

在这里插入图片描述

Socket:由 IP 地址和端口号组成
序列号:用来解决乱序问题
窗口大小:用来做流量控制

(2)TCP 四元组可以唯一的确定一个TCP连接:

在这里插入图片描述

  • 源地址和目的地址的字段(32位): 在 IP 头部中,作用是通过 IP 协议发送报文给对方主机。

  • 源端口和目的端口的字段(16位): 在 TCP 头部中,作用是告诉 TCP 协议应该把报文发给哪个进程。

二、TCP 连接建立

TCP 是面向连接的协议,所以使用 TCP 前必须先建立连接,而建立连接是通过三次握手而进行的。

1、TCP 三次握手过程

在这里插入图片描述
一开始,客户端和服务端都处于 CLOSED 状态,先是服务端主动监听某个端口,处于 LISTEN 状态。

(1)第一次握手(客户端向服务端发送一段SYN报文)

客户端会随机初始化序号client_isn),将此序号置于 TCP 首部的序号字段中,同时把 SYN 标志位置为 1 ,表示 SYN 报文,接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于 SYN-SENT 状态。
在这里插入图片描述

  • 标记位为SYN,表示请求建立连接
  • 序号为Seq=X(X一般为1)
  • 客户端结束CLOSED状态,进入SYN-SENT阶段。、

(2)第二次握手(服务端接受到来自客户端的SYN报文,返回一段SYN+ACK报文)

服务端收到客户端的 SYN 报文后结束LISTEN阶段,首先服务端也随机初始化自己的序号(server_isn),将此序号填入 TCP 首部的序号字段中,其次把 TCP 首部的确认应答号字段填入 client_isn + 1, 接着把 SYN 和 ACK 标志位置为 1。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 SYN-RCVD 状态。
在这里插入图片描述

  • 标志位为SYN和ACK,表示客户端的报文Seq序号有效(服务端能正常接受客户端发送的数据),并同意创建新连接。
  • 序号为Seq=y,
  • 确认号为Ack=x+1,表示收到客户端的序号Seq并将其加1作为自己确认号Ack的值,随后服务器端进入SYN-RCVD阶段。

(3)第三次握手(客户端接受到来自服务端的SYN+ACK报文,返回一段ACK报文)

客户端收到服务端报文后,明确了从客户端到服务端的数据传输是正常的,向服务端回应最后一个应答报文,首先该应答报文 TCP 首部 ACK 标志位置为 1 ,其次确认应答号字段填入 server_isn + 1 ,最后把报文发送给服务端,这次报文可以携带客户到服务器的数据,之后客户端处于 ESTABLISHED 状态。
服务器收到客户端的应答报文后,也进入 ESTABLISHED 状态。
在这里插入图片描述

  • 其中标志位为ACK,表示收到服务端同意连接的信号了。
  • 序号为Seq=x+1,表示确认收到服务器端的确认号Ack,并将其作为自己的序号值。
  • 确认号为Ack=y+1,表示收到服务器端序号Seq,并将其加1作为自己的确认号Ack的值。
  • 客户端进入ESTABLISHED阶段

注意:

  • 从上面的过程可以发现只有第三次握手是可以携带数据的,前两次握手都是不可以携 带数据的,一旦完成三次握手,双方都处于 ESTABLISHED 状态,连接就已建立完成,客户端和服务端就可以相互发送数据了。
  • 在 Linux 可以通过 netstat -napt 命令查看TCP 的连接状态

2、为什么是三次握手?不是两次、四次?

(1)避免历史连接

为了防止旧的重复连接初始化造成混乱,网络环境是错综复杂的,先发送的数据包,可能会由于网络拥堵等原因,不会按时到达目标主机,使得旧的数据包先到达目标主机,TCP通过三次握手避免了这种情况的发生。

在这里插入图片描述
客户端连续发送多次 SYN 建立连接的报文,在网络拥堵等情况下:

  • 一个「旧 SYN 报文」比「最新的 SYN 」 报文早到达了服务端;
  • 那么此时服务端就会回一个 SYN + ACK 报文给客户端;
  • 客户端收到后可以根据自身的上下文,判断这是一个历史连接(序列号过期或超时),那么客户端就会发送 RST 报文给服务端,表示中止这一次连接。

如果是两次握手连接,就不能判断当前连接是否是历史连接,三次握手则可以在客户端(发送方)准备发送第三次报文时,客户端因有足够的上下文来判断当前连接是否是历史连接:

  • 如果是历史连接(序列号过期或超时),则第三次握手发送的报文是 RST 报文,以此中止历史连接;
  • 如果不是历史连接,则第三次发送的报文是 ACK 报文,通信双方就会成功建立连接;

所以, TCP 使用三次握手建立连接的最主要原因是防止历史连接初始化了连接

(2)同步双方初始序列号

TCP 协议的通信双方, 都必须维护一个序列号, 序列号是可靠传输的一个关键因素,它的作用:

  • 接收方可以去除重复的数据;
  • 接收方可以根据数据包的序列号按序接收;
  • 可以标识发送出去的数据包中, 哪些是已经被对方收到的;

序列号在 TCP 连接中占据着非常重要的作用,所以当客户端发送携带初始序列号的 SYN 报文的时候,需要服务端返回一个 ACK 应答报文,表示客户端的 SYN 报文已被服务端成功接收,那么当服务端发送初始序列号给客户端的时候,依然也要得到客户端的应答回应,这样一来一回,才能确保双方的初始序列号能被可靠的同步。

在这里插入图片描述

  • 四次握手其实也能够可靠的同步双方的初始化序号,但由于第二步和第三步可以优化成一步,所以就成了三次握手。
  • 而两次握手只保证了一方的初始序列号能被对方成功接收,没办法保证双方的初始序列号都能被确认接收。
  • 客户端和服务端的初始序列号 ISN 是不相同的
    因为网络中的报文会延迟、会复制重发、也有可能丢失,这样会造成的不同连接之间产生互相影响,为了避免互相影响,客户端和服务端的初始序列号是随机且不同的。

(3)避免资源浪费

如果只有两次握手,当客户端的 SYN 请求连接在网络中阻塞,客户端没有接收到 ACK 报文,就会重复发送多次 SYN 报文,由于没有第三次握手,服务器不清楚客户端是否收到了自己发送的建立连接的 ACK 确认信号,所以每收到一个 SYN 就只能先主动建立一个连接,建立了多个冗余的无效链接,造成不必要的资源浪费。
在这里插入图片描述

  • 即两次握手会造成消息滞留情况下,服务器重复接受无用的连接请求SYN报文,重复分配资源,造成不必要的资源浪费。

(4)小结

  • TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号,序列号能够保证数据包不重复、不丢弃和按序传输。
  • 两次握手:无法避免历史错误连接的初始化,浪费接收方的资源,无法可靠的同步双方序列号;
  • 四次握手:TCP 协议的设计可以让我们同时传递 ACK 和 SYN 两个控制信息,三次握手是理论上最少可靠连接建立,不需要使用更多的通信次数传输相同的信息;

三、TCP 连接断开

TCP通过四次挥手方式 断开连接,服务端和客户端都可以主动断开连接,断开连接后主机中的资源将被释放。

1、TCP 四次挥手过程

在这里插入图片描述
一开始,客户端和服务端都处于 ESTABLISHED 状态。

(1)第一次挥手(客户端向服务端发送一段FIN报文)

客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,随后客户端进入 FIN_WAIT_1 状态。

  • 标记为FIN ,表示请求释放连接
  • 序号为Seq=U;
  • FIN_WAIT_1状态,即半关闭状态,停止在客户端到服务端方向上发送数据,但是客户端任然能接受从服务端传输过来的数据。

(2)第二次挥手(服务端向客户端发送一段ACK报文)

服务端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,就向客户端发送 ACK 应答报文,随后服务端进入CLOSED_WAIT阶段(半关闭状态),客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。

  • 标记为ACK,表示接收到客户端发送的释放连接的请求;
  • 序号Seq=V;
  • 确认号为Ack=U+1,表示是在收到客户端报文的基础上,将其序号Seq+1作为本段报文确认号Ack的值;
  • 随后服务端开始准备释放服务器端到客户端方向上的连接;

(3)第三次挥手(服务端再次向客户端发送一段FIN报文)

等待服务端处理完数据,做好了释放服务端到客户端方向上的连接准备,也向客户端发送 FIN 报文,之后服务端进入LAST_ACK 状态。

  • 标记位为FIN、ACK ,表示已经准备好释放连接了,
  • 序号为Seq=W;
  • 确认号为Ack=U+1;表示是在收到客户端报文的基础上,将其序号Seq+1作为本段报文确认号Ack的值。
  • 随后服务端结束CLOSED_WAIT阶段,进入LAST_ACK 阶段,并且停止在服务端到客户端上发送数据,但是服务器端仍然能够接受从客户端传输过来的数据

(4)第四次挥手(客户端向服务端发送一段ACK报文)

客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME_WAIT 状态。服务器收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端已经完成连接的关闭客户端在经过 2MSL 一段时间后,自动进入 CLOSE 状态,至此客户端也完成连接的关闭。

  • 标记为ACK,表示接收到服务器准备好释放连接的信号
  • 序号为Seq=U+1,表示是在收到了服务端报文的基础上,将其确认号Ack作为本段报文序号的值。
  • 确认号为Ack=W+1,表示是在收到了服务器端报文的基础上,将其序号Seq值作为本段报文确认号的值。

注意:

  • 主动关闭连接的,才有 TIME_WAIT 状态。
  • 每个方向都需要一个 FIN 和一个ACK,因此通常被称为四次挥手。

2、为什么建立连接的时候是三次?断开连接的时候是四次?

服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,从而比三次握手多了一次。

  • 建立连接时,服务端收到客户端的SYN报文后,会直接发送SYN+ACK连接报文,其中ACK报文是直接用来应答的,SYN报文是用来同步的。
  • 断开连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。服务端收到FIN报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端处理完数据后,才发送 FIN 报文给客户端来表示同意现在关闭连接。

3、为什么 TIME_WAIT 等待的时间是 2MSL?

MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。

  • 网络中可能存在来自发送方的数据包,当这些发送方的数据包被接收方处理后又会向对方发送响应,所以一来一回需要等待 2 倍的时间。
    比如,如果被动关闭方没有收到断开连接的最后的 ACK 报文,就会触发超时重发 FIN 报文,另一方接收到 FIN 后,会重发 ACK 给被动关闭方, 一来一去正好 2 个 MSL。

  • 2MSL 的时间是从客户端接收到 FIN 后发送 ACK 开始计时的。如果在 TIME-WAIT 时间内,客户端的 ACK 没有传输到服务端,客户端又接收到了服务端重发的 FIN 报文,那么 2MSL 时间将重新计时。

在 Linux 系统里 2MSL 默认是 60 秒,那么一个 MSL 也就是 30 秒。Linux 系统停留在 TIME_WAIT 的时间为固定的 60 秒。如果要修改 TIME_WAIT 的时间长度,只能修改 Linux 内核代码里 TCP_TIMEWAIT_LEN 的值,并重新编译 Linux 内核。

四、补充

1、 TIME_WAIT 状态

主动发起关闭连接的一方,才会有 TIME_WAIT 状态。

(1)为什么需要 TIME_WAIT 状态?

  • 防止具有相同四元组的旧数据包被收到;
    假设 TIME-WAIT 没有等待时间或时间过短,被延迟的报文抵达客户端后,客户端是有可能正常接收这个过期的报文,这就会产生数据错乱等严重的问题。
    TCP 就设计出了这么一个机制,经过 2MSL 这个时间,足以让两个方向上的数据包都被丢弃,使得原来连接的数据包在网络中都自然消失,再出现的数据包一定都是新建立连接所产生的。
  • 保证被动关闭连接的一方能被正确的关闭,等待足够的时间以确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。
    假设客户端四次挥手的最后一个 ACK 报文在网络中被丢失了,此时如果客户端 TIME-WAIT 过短或没有,则就直接进入了 CLOSE 状态了,那么服务端则会一直处在 LASE-ACK 状态。当客户端发起建立连接的 SYN 请求报文后,服务端会发送 RST 报文给客户端,连接建立的过程就会被终止。
    客户端在 TIME-WAIT 状态等待 2MSL 时间后,就可以保证双方的连接都可以正常的关闭。

(2)TIME_WAIT 过多有什么危害?

  • 占用内存资源;
  • 占用端口资源,一个 TCP 连接至少消耗一个本地端口;如果服务端 TIME_WAIT 状态过多,占满了所有端口资源,则会导致无法创建新连接。

(3)如何优化 TIME_WAIT?

  • 打开 net.ipv4.tcp_tw_reuse 和 net.ipv4.tcp_timestamps 选项;
  • net.ipv4.tcp_max_tw_buckets
  • 程序中使用 SO_LINGER ,应用强制使用 RST 关闭。

2、SYN 攻击

我们都知道 TCP 连接建立是需要三次握手,假设攻击者短时间伪造不同 IP 地址的 SYN 报文,服务端每接收到一个 SYN 报文,就进入SYN_RCVD 状态,但服务端发送出去的 ACK + SYN 报文,无法得到未知 IP 主机的 ACK 应答,久而久之就会占满服务端的 SYN 接收队列(未连接队列),使得服务器不能为正常用户服务。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值