网络协议-TCP、UDP区别及TCP三次握手、四次挥手

三次握手与四次挥手面试问题
三次握手和四次挥手

网络的五层划分

  • 应用层
    常见协议:HTTP (Hyper Text Transfer Protocol),FTP(文件传输协议),DNS(域名解析协议)
  • 传输层
    常见协议:TCP(传输控制协议),UDP(用户数据报协议)
  • 网络层
    常见协议:IP
  • 数据链路层
  • 物理层

详解 TCP 协议特点

TCP 是传输层协议,对应 OSI 网络模型的第四层传输层,特点如下。

  • TCP 协议是基于链接的,也就是传输数据前需要先建立好链接,然后再进行传输。
  • TCP 链接一旦建立,就可以在链接上进行双向的通信。
  • TCP 的传输是基于字节流而不是报文,将数据按字节大小进行编号,接收端通过 ACK 来确认收到的数据编号,通过这种机制,TCP 协议能够保证接收数据的有序性和完整性,因此 TCP 能够提供可靠性传输。
  • TCP 还能提供流量控制能力,通过滑动窗口来控制数据的发送速率。滑动窗口的本质是动态缓冲区,接收端根据自己的处理能力,在 TCP 的 Header 中动态调整窗口大小,通过 ACK 应答包通知给发送端,发送端根据窗口大小调整发送的的速度。
  • 仅仅有了流量控制能力还不够,TCP 协议还考虑到了网络问题可能会导致大量重传,进而导致网络情况进一步恶化,因此 TCP 协议还提供拥塞控制。TCP 处理拥塞控制主要用到了慢启动、拥塞避免、拥塞发生、快速恢复四个算法。

TCP 和 UDP 的区别

  • TCP/UDP都属于传输层协议
  • TCP是面向连接的传输层协议,能够准确可靠的把数据传递给对方,当数据有丢包情况会重发,但是需要在建立和断开连接需要至少7次的发包和收包,会浪费网络流量,主要用在对可靠性要求较高的地方
  • UDP是面向无连接的传输层协议,即只负责传输数据,不能确保对方是否收到数据和数据的正确顺序,数据的正确性由应用层来校验,主要用于高传输和实时性要求较高的场合如音视频会议,广播。

序列号,确认号

  • 序列号seq(Sequence Numbers):用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记
  • 确认序号ACK(Acknowledge Number):在接收端,用来通知发送端数据成功接收;其数值等于发送方的发送序号+1(即接收方期望接收的下一个序列号);
  • 标志位:
    (A)SYN:创建一个连接
    (B)ACK:确认序号有效
    (C)FIN:终结一个连接
    (D)RST:重置连接。
    (E)PSH:接收方应该尽快将这个报文交给应用层。
    (F)URG:紧急指针(urgent pointer)有效。

详解三次握手建连

TCP 是基于链接的,所以在传输数据前需要先建立链接,TCP 在传输上是双工传输,不区分 Client 端与 Server 端,为了便于理解,我们把主动发起建连请求的一端称作 Client 端,把被动建立链接的一端称作 Server 端。

如下图,建连的时序是从上到下,左右两边的绿色字分别代表 Client 端与 Server 端当时的链接状态。


首先建立链接前需要 Server 端先监听端口,因此 Server 端建立链接前的初始状态就是 LISTEN 状态,这时 Client 端准备建立链接,先发送一个 SYN 同步包,发送完同步包后,Client 端的链接状态变成了 SYN_SENT 状态。Server 端收到 SYN 后,同意建立链接,会向 Client 端回复一个 ACK。

由于 TCP 是双工传输,Server 端也会同时向 Client 端发送一个 SYN,申请 Server 向 Client 方向建立链接。发送完 ACK 和 SYN 后,Server 端的链接状态就变成了 SYN_RCVD。

Client 收到 Server 的 ACK 后,Client 端的链接状态就变成了 ESTABLISHED 状态,同时,Client 向 Server 端发送 ACK,回复 Server 端的 SYN 请求。

Server 端收到 Client 端的 ACK 后,Server 端的链接状态也就变成了的 ESTABLISHED 状态,此时建连完成,双方随时可以进行数据传输。

需要明白三次握手是为了建立双向的链接,需要记住 Client 端和 Server 端的链接状态变化。另外回答建连的问题时,可以提到 SYN 洪水攻击发生的原因,就是 Server 端收到 Client 端的 SYN 请求后,发送了 ACK 和 SYN,但是 Client 端不进行回复,导致 Server 端大量的链接处在 SYN_RCVD 状态,进而影响其他正常请求的建连。可以设置 tcp_synack_retries = 0 加快半链接的回收速度,或者调大 tcp_max_syn_backlog (队列中半链接数)来应对少量的 SYN 洪水攻击

详解四次挥手断连

TCP 的断连,如下图所示。


TCP 链接的关闭,通信双方都可以先发起,我们暂且把先发起的一方看作 Client,从图中看出,通信中 Client 和 Server 两端的链接都是 ESTABLISHED 状态,然后 Client 先主动发起了关闭链接请求,Client 向 Server 发送了一个 FIN 包,表示 Client 端已经没有数据要发送了,然后 Client 进入了 FIN_WAIT_1 状态。

Server 端收到 FIN 后,返回 ACK,然后进入 CLOSE_WAIT 状态。此时 Server 属于半关闭状态,因为此时 Client 向 Server 方向已经不会发送数据了,可是 Server 向 Client 端可能还有数据要发送。

当 Server 端数据发送完毕后,Server 端会向 Client 端发送 FIN,表示 Server 端也没有数据要发送了,此时 Server 进入 LAST_ACK 状态,就等待 Client 的应答就可以关闭链接了。

Client 端收到 Server 端的 FIN 后,回复 ACK,然后进入 TIME_WAIT 状态。TIME_WAIT 状态下需要等待 2 倍的最大报文段生存时间,来保证链接的可靠关闭,之后才会进入 CLOSED 关闭状态。而 Server 端收到 ACK 后直接就进入 CLOSED 状态。

为什么需要等待 2 倍最大报文段生存时间之后再关闭链接,原因有两个:

  1. 保证 TCP 协议的全双工连接能够可靠关闭;
  2. 保证这次连接的重复数据段从网络中消失,防止端口被重用时可能产生数据混淆。

从这个交互流程可以看出,无论是建连还是断链,都是需要在两个方向上进行,只不过建连时,Server 端的 SYN 和 ACK 合并为一次发送,而断链时,两个方向上数据发送停止的时间可能不同,所以不能合并发送 FIN 和 ACK。这就是建连三次握手而断链需要四次的原因。

另外回答断链的问题时,可以提到实际应用中有可能遇到大量 Socket 处在 TIME_WAIT 或者 CLOSE_WAIT 状态的问题。一般开启 tcp_tw_reuse 和 tcp_tw_recycle 能够加快 TIME-WAIT 的 Sockets 回收;而大量 CLOSE_WAIT 可能是被动关闭的一方存在代码 bug,没有正确关闭链接导致的。

  • 为什么要等待 2MSL
    客户端发送的第4次握手报文,服务器没有收到。这时候服务器端会再次发送一个 FIN =1 的报文,而这个时候客户端还处于 TIME_WAIT 状态,所以可以再次发送确认消息。

如果有大量的连接,每次在连接、关闭时都要经历三次握手、四次挥手,这很显然会造成性能低下。因此,HTTP 有一种叫作 keepalive connections 的机制,它可以在传输数据后仍然保持连接,当客户端需要再次获取数据时,直接使用刚刚空闲下来的连接而无须再次握手。

  • 为什么需要三次握手,两次确认?
    为什么客户端还要发送一次确认呢,主要是为了防止已失效的链接请求报文突然又传到了服务器端,造成错误。比如:客户端发送链接请求,因为网络或者一些其它因素造成没有在一定时间到达服务器端,所以客户没有收到确认。由于客户端会重发一次链接请求,通过三次握手与服务器建立连接,但是这时上次的请求到达服务器端了,服务器会误以为客户端又发了一次新的链接请求,会向客户端发送报文同意建立连接,但是客户端已经建立连接了,就会放弃该报文,服务端没有收到响应,也就不会建立连接了。

  • 三次握手出现错误时的应对措施?
    第一次握手A发送SYN传输失败,A,B都不会申请资源,连接失败。如果一段时间内发出多个SYN连接请求,那么A只会接受它最后发送的那个SYN的SYN+ACK回应,忽略其他回应全部回应,B中多申请的资源也会释放

    第二次握手B发送SYN+ACK传输失败,A不会申请资源,B申请了资源,但收不到A的ACK,过一段时间释放资源。如果是收到了多个A的SYN请求,B都会回复SYN+ACK,但A只会承认其中它最早发送的那个SYN的回应,并回复最后一次握手的ACK

    第三次握手ACK传输失败,B没有收到ACK,释放资源,对于后序的A的传输数据返回RST(重置连接)。实际上B会因为没有收到A的ACK会多次发送SYN+ACK,次数是可以设置的,如果最后还是没有收到A的ACK,则释放资源,对A的数据传输返回RST

推荐阅读更多精彩内容