浅学计网:TCP三握四挥

2023-11-16 15:32:23 浏览数 (3)

TCP的三次握手

2.6.1 三次握手细节

在网络数据传输中,传输层协议TCP是要建立连接的可靠传输,TCP建立连接的过程,我们称为三次握手。

  1. 第一次握手: 客户端将SYN置1,随机产生一个初始序列号 seq发送给服务端,进入SYN_SENT状 态。
  2. 第二次握手: 服务端 收到 客户端 的SYN=1 之后,知道客户端请求建立连接,将自己的SYN置1,ACK 置1,产生一个acknowledge number=sequence number 1,并随机产生一个自己的初始序列号seq,发送给客户端;进入SYN_RCVD状态。
  3. 第三次握手: 客户端检查acknowledge number是否为序列号 1,ACK是否为1,检查正确之后将 自己的ACK置为1,产生一个acknowledge number=服务器发的序列号 1,发送给服务器,进入 ESTABLISHED状态。 服务器检查ACK为1和acknowledge number为序列号 1之后,也进入 ESTABLISHED状态。

完成三次握手,连接建立。

简单来说:

  1. 客户端向服务端发送SYN。
  2. 服务端返回SYN和ACK。
  3. 客户端返回ACK。
2.6.2 借助现实理解三次握手

三次握手的目的是建立可靠的通信信道,主要的目的就是 双方确认自己与对方可以正常发送与接收

  1. 第一次握手:
    • 客户端什么都不能确认。
    • 服务器确认了对方发送正常。
  2. 第二次握手:
    • 客户端确认了:自己发送和接收正常,对方发送和接收正常。
    • 服务端确认了:自己接收正常、对方发送正常。
  3. 第三次握手:
    • 客户端确认了:自己发送和接收正常,对方发送和接收正常。
    • 服务端确认了:自己发送和接收正常,对方发送和接收正常。

所以三次握手就能确认双发收发功能都正常,缺一不可。

2.6.3 建立连接可以只握手两次吗

不可以

因为可能会出现已失效的连接请求报文段又传到了服务器端。

客户端 发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达服务端。本来这是一个早已失效的报文段。但 服务端 收到此失效的连接请求报文段后,就误认为 是 客户端 再次发出的一个新的连接请求。于是就向 客户端 发出确认报文段,同意建立连接。

假设 不采用 “三次握手”,那么只要 服务端 发出确认,新的连接就建立了。由于现在 客户端 并没有发出 建立连接的请求,因此不会理睬 服务端 的确认,也不会向 服务端 发送数据。但 服务端 却以为新 的运输连接已经建立,并一直等待 客户端 发来数据。这样,服务端 的很多资源就白白浪费掉了。

采用 “三次握手” 的办法可以防止上述现象发生。例如刚才那种情况,客户端 不会向 服务端的确认 发出确认。服务端 由于收不到确认,就知道 客户端 并没有要求建立连接。

而且,两次握手无法保证 客户端 正确接收第二次握手的报文(服务端 无法确认 客户端 是否收到), 也无法保证 客户端 和 服务端 之间成功互换初始序列号。

2.6.4 可以四次握手吗

这个肯定可以。三次握手都可以保证连接成功了,何况是四次,但是会降低传输的效率。

2.6.5 第三次握手中,如果客户端ACK未送达服务器,会怎样?
  • 服务端:由于 服务端 没有收到 ACK确认,因此会每隔 3秒 重发之前的 SYN ACK(默认重发五 次,之后自动关闭连接进入CLOSED状态),客户端 收到后会重新传ACK给 服务端。
  • 客户端:
    1. 情况一:在 服务端 进行超时重发的过程中,如果 客户端 向服务器发送数据,数据头部的ACK是为1的, 所以服务器收到数据之后会读取 ACK number,进入 ESTABLISH状态。
    2. 情况二:在服务端进入CLOSED状态之后,如果客户端向服务器发送数据,服务器会以RST包应答。
2.6.6 建立连接后,客户端出现问题

服务器每收到一次客户端的请求后都会重新复位一个计时器,时间通常是设置为2小时,若两小时 还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

2.6.7 初始序列号是什么

TCP连接的一方A,随机选择一个32位的序列号(Sequence Number)作为发送数据的初始序列号(Initial Sequence Number,ISN),比如为1000,以该序列号为原点,对要传送的数据进行 编号:1001、1002... 三次握手时,把这个初始序列号传送给另一方B,以便在传输数据时,B可以确认什么样的数据编号是合法的;同时在进行数据传输时,A还可以确认B收到的每一个字节,如果A收到了B的确认编号(acknowledge number)是2001,就说明编号为1001-2000的数据已经被B成功接受。

2.6.8 SYN洪泛攻击

SYN洪泛攻击属于 DOS 攻击的一种,它利用 TCP 协议缺陷,通过发送大量的半连接请求,耗费 CPU 和内存资源。

原理

  • 在三次握手过程中,服务器发送 [SYN/ACK] 包(第二个包)之后、收到客户端的 [ACK] 包(第三个包)之前的 TCP 连接称为半连接(half-open connect),此时服务器处于 SYN_RECV(等待客户端响应)状态。如果接收到客户端的 [ACK],则 TCP 连接成功,如果未接受到,则会不断重发请求直至成功。
  • SYN 攻击的攻击者在短时间内伪造大量不存在的 IP 地址,向服务器不断地发送 [SYN] 包,服务器回复 [SYN/ACK] 包,并等待客户的确认。由于源地址是不存在的,服务器需要不断的重发直至超时。
  • 这些伪造的 [SYN] 包将长时间占用未连接队列,影响了正常的 SYN,导致目标系统运行缓慢、网络堵塞甚至系统瘫痪。

检测

当在服务器上看到大量的半连接状态时,特别是源 IP 地址是随机的,基本上可以断定这是一次 SYN 攻击。

防范

  • 通过防火墙、路由器等过滤网关防护。
  • 通过加固 TCP/IP 协议栈防范,如增加最大半连接数,缩短超时时间。
    • 减少SYN timeout时间。在握手的第三步,服务器会等待30秒-120秒的时间,减少这个等待时间就能释放更多的资源。
    • 限制同时打开的SYN半连接数目。
  • SYN Cookies 技术。SYN Cookies 是对 TCP 服务器端的三次握手做一些修改,专门用来防范 SYN 洪泛攻击的一种手段。

2.7 TCP的四次挥手

2.7.1 四次挥手细节

在网络数据传输中,传输层协议断开连接的过程我们称为四次挥手。

  1. 第一次挥手: 客户端 将FIN置为1,发送一个序列号seq给 服务端并进入FIN_WAIT_1状态;
  2. 第二次挥手: 服务端 收到 FIN之后,发送一个ACK=1acknowledge number=收到的序列号 1并 进入CLOSE_WAIT状态。 此时客户端已经没有要发送的数据了,但仍可以接受服务器发来的数据。
  3. 第三次挥手: 服务端 将FIN置1,发送一个序列号客户端;进入LAST_ACK状态。
  4. 第四次挥手: 客户端 收到服务器的FIN后,进入TIME_WAIT状态; 接着将ACK置1,发送一个 acknowledge number=序列号 1给服务器; 服务器收到后,确认acknowledge number后,变为 CLOSED状态,不再向客户端发送数据。 客户端等待2 * MSL(报文段最长寿命)时间后,也进入 CLOSED状态。 完成四次挥手。
2.7.2 借助现实理解四次挥手

四次挥手断开连接是因为要确定数据全部传输完了

  1. 客户端与服务器交谈结束之后,客户端要结束此次会话,就会对服务器说:我要关闭连接了(第一次挥手)。
  2. 服务器收到客户端的消息后说:好的,知道你要关闭连接了。(第二次挥手)
  3. 然后服务器确定了没有话要和客户端说了,服务器就会对客户说,我要关闭连接了。(第三次挥手)
  4. 客户端收到服务器要结束连接的消息后说:已收到你要关闭连接的消息。(第四次挥手),才关闭。
2.7.3 CLOSE_WAIT 状态意义是什 么

为什么不能把服务器发送的ACK和FIN合并起来,变成三次挥手,CLOSE_WAIT状态意义是什么?

因为服务器收到客户端断开连接的请求时,可能还有一些数据没有发完,这时先回复ACK,表示接收到了断开连接的请求。等到数据发完之后再发FIN,断开服务器到客户端的数据传送。

2.7.4 如果第二次挥手时服务端的ACK没有送达客户端

客户端没有收到ACK确认,会重新发送FIN请求。

2.7.5 客户端 TIME_WAIT 状态的意义

第四次挥手时,客户端发送给服务器的ACK有可能丢失,TIME_WAIT状态就是用来重发可能丢失的 ACK报文

如果 服务端 没有收到ACK,就会重发FIN,如果 客户端 在 2*MSL(报文段最长寿命) 的时间内收到了FIN,就会重新发送ACK并再次等待2 * MSL,防止服务端没有收到ACK而不断重发FIN

MSL(Maximum Segment Lifetime),指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的 最大时间。如果直到2MSL,客户端 都没有再次收到FIN,那么 客户端 推断ACK已经被成功接收,则 结束TCP连接。

2.7.6 TIME-WAIT 状态过多

TIME-WAIT 状态过多会产生什么后果?怎样处理?

  • 从服务器来讲: 短时间内关闭了大量的 客户端 连接,就会造成服务器上出现大量的TIME_WAIT连接,严重消耗着服务器的资源,此时部分客户端就会显示连接不上。
  • 从客户端来讲: 客户端TIME_WAIT过多,就会导致端口资源被占用,因为端口就65536个,被占满就会导致无法创建新的连接。

解决方法

  • 服务器可以设置 SO_REUSEADDR套接字选项来避免 TIME_WAIT状态,此套接字选项告诉内核,即使此端口正忙(处于TIME_WAIT状态),也请继续并重用它。
  • 调整系统内核参数,修改/etc/sysctl.conf文件,即修改net.ipv4.tcp_tw_reuse 和 tcp_timestamps net.ipv4.tcp_tw_reuse = 1 # 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭; net.ipv4.tcp_tw_recycle = 1 # 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
  • 强制关闭,发送 RST 包越过TIME_WAIT状态,直接进入CLOSED状态。
2.7.7 TIME_WAIT是谁的状态

TIME_WAIT 是主动断开连接的一方会进入的状态,一般情况下,都是客户端所处的状态,服务器端一般设置不主动关闭连接。

TIME_WAIT 需要等待 2*MSL,在大量短连接的情况下,TIME_WAIT会太多,这也会消耗很多系统资源。对于服务器来说,在 HTTP 协议里指定 KeepAlive(浏览器重用一个 TCP 连接来处理多个 HTTP 请求),由浏览器来主动断开连接,可以一定程度上减少服务器的这个问题。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞