TCP 和 UDP 协议简介

一、TCP

TCP(Transmission Control Protocol),传输控制协议,对“传输、发送、通信”进行“控制”的协议,它充分地实现了数据传输时的各种控制功能,可以进行丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。此外,TCP 是面向有连接的协议,只有在确认通信端存在时才会发送数据。

TCP 是一个传输层协议,提供 Host-To-Host 数据的可靠传输,支持全双工,是一个连接导向的协议。

TCP 复杂控制连接的建立、断开、保持等管理工作,保证了在 IP 这种无连接的网络上也能够实现高可靠性的通信。

TCP 使用场景:

  • 远程控制(SSH)
  • File Transfer Protocol(FTP)
  • 邮件(SMTP、IMAP)等
  • 点对点文件传出(微信等)

1. 数据发送

TCP 协议有这样几个基本操作:

  • 一个 Host 主动向另一个 Host 发起连接,称为 SYN(Synchronization),请求同步;
  • 一个 Host 主动断开请求,称为 FIN(Finish),请求完成;
  • 一个 Host 给另一个 Host 发送数据,称为 PSH(Push),数据推送;

在 TCP 中,当发送端的数据到达接收主机时,接收端主机会返回一个已收到消息的通知,这个消息叫做确认应答(ACK)。如果在一定时间内没有收到 ACK,发送端就可以认为数据已经丢失,并进行重发。

在 TCP 中,会在发送数据的每一个字节都标上序号,接收端查询接收数据 TCP 首部中的序列号和数据的长度,将自己下一步应该接收的序号作为 ACK 返送回去。序列号机制使发送端可以根据序列号分批次发送,使接收端可以处理消息乱序和重复问题。

在 TCP 中,会在每次发包时计算往返时间及其偏差(方差),将这个往返时间和偏差(方差)相加就是 重发超时时间。当然,最初的数据包还不知道往返时间,其重发超时一般设置为 6 秒左右。若数据被重发之后还是收不到 ACK,则进行再次发送,此时,重发超时时间会以 2 倍、4 倍的指数函数延长。

当数据达到一定的重发次数之后,如果仍没有任何 ACK 返回,就会判断为网络或对端主机发生了异常,强制关闭连接。

2. 连接管理

TCP 连接过程就是我们再熟悉不过的三次握手和四次挥手过程。TCP 是一个双工协议,为了让双方都保证,建立连接的时候,连接双方都需要向对方发送 SYN 和 ACK。

  1. 客户端发送消息给服务端(SYN);
  2. 服务端准备好进行连接,针对客户端的 SYN 给一个 ACK,并同时发送一个 SYN 给客户端;
  3. 客户端准备就绪,给服务端发送一个 ACK;

  4. 客户端要求断开连接,发送一个断开的请求 —— FIN;
  5. 服务端收到请求,然后给客户端一个 ACK,作为 FIN 的响应;
  6. 服务端把要处理的任务执行完,比如发送出去的消息还没有得到响应、资源还没得到释放等。服务端经过一个等待,确定可以关闭连接了,再发一个 FIN 给客户端;
  7. 客户端收到请求,然后给服务端一个 ACK,作为 FIN 的响应,连接断开;

FIN,其实就是我不会再发数据,但是你还可以发数据给我。

3. 段和窗口控制

TCP 以段(Segment)为单位发送数据,段的大小(MSS:Maximum Segment Size)是在三次握手的时候,在两端主机之间被计算得出。两端的主机在发出建立连接的请求时,会在 TCP 首部中写入 MSS 选项,告诉对方自己的接口能够适应的 MSS 的大小,然后 TCP 会在两者之间选择一个较小的值投入使用。下面是一份段结构:

TCP 段的大小(MSS)涉及发送、接收缓冲区的大小设置,双方实际发送接收封包的大小,对拆包和粘包的过程有指导作用,因此需要双方去协商。如果这个值设置的非常大,会降低性能,比如内存使用、资源占用等;如果这个值设置的非常小,会浪费传输资源(降低吞吐量);

TCP 以段为单位,每发一个段进行一次 ACK 的处理,这样的传输方式有一个缺点 —— 包的往返时间越长通信性能就越低。为解决这个问题,TCP 引入了 窗口 这个概念,窗口是比段更大的单位,在窗口内发送了一个段以后不必要一直等待 ACK,而是继续发送。如下图,窗口大小为 4 个段。

有了窗口,发送方利用滑动窗口算法发送消息;接收方构造缓冲区接收消息,并给发送方 ACK。如下图,这时候滑动窗口可以向右滑动。

在使用窗口控制中,如果出现段丢失该怎么办?这个问题可以分为两种情况,第一种情况是接收端接收到了数据,但是回复 ACK 失败,这种情况是不需要再进行重发的,接收端会在下一次的 ACK 中告知数据接收成功了;第二种情况是接收端未收到数据,接收端会一直 ACK 该数据的序列号,当发送端连续 3 次接收同一序列号的 ACK,就会将其对应的数据进行重发,该机制称为 高效重发机制

4. 流控制

流控制体现为可以让发送端根据接收端的实际接收能力控制发送的数据量。它的具体操作是,接收端主机向发送端主机通知自己可以接收数据的大小,于是发送端会发送不超过这个限度的数据,该大小限度就被称为窗口大小。

实际操作中,每个 TCP 段的大小不同,限制数量会让接收方的缓冲区不好操作,因此实际操作中窗口大小单位是字节数。

接收端的数据缓冲区一旦面临溢出时,窗口大小的值也会被随之设置为一个更小的值通知给发送端。发送端再根据该值,对发送数据的量进行控制。这就形成了一个完整的 TCP 流控制。

5. 拥塞控制

拥塞控制是为了解决网络拥堵的问题,在网络出现拥堵时,如果突然发送一个较大量的数据,极有可能会导致整个网络的瘫痪。前面提到的流控制,窗口大小是由接收端决定的,发送端无法自我调节要发送的数据量。

为了在发送端调节所要发送数据的量,定义了一个叫做 拥塞窗口 的概念。在通信一开始时,通过一个叫做慢启动的算法计算出拥塞窗口的初始阈值,之后每收到一次 ACK,拥塞窗口按照一定的比例放大拥塞窗口。在发送数据包时,将拥塞窗口的大小与接收端主动通知的窗口大小做比较,然后按照它们当中较小的那个值,发送比其还要小的数据量。

当 TCP 通信开始以后,网络吞吐量会逐渐上升,但是随着网络拥堵的发生(体现为数据重发)吞吐量也会急速下降。于是会再次进入吞吐量慢慢上升的过程。因此所谓 TCP 的吞吐量的特点就好像是在逐步占领网络带宽的感觉。

6. Nagle 算法

Nagle 算法是指发送端即使还有应该发送的数据,但如果这部分数据很少的话,则进行延迟发送的一种处理机制。具体来说,就是仅在下列任意一种条件下才能发送数据。

  • 已发送的数据都已经收到 ACK
  • 已发送最大段长度(MSS)的数据

7. 延迟确认应答

前面提到,TCP 采用滑动窗口的控制机制,因此通常确认应答少一些也无妨。为此,引入了一个方法,那就是收到数据以后并不立即返回 ACK,而是延迟一段时间的机制。

  • 在没有收到 2x最大段长度(MSS)的数据为止不做 ACK,体现为每两个数据段返回一个 ACK。
  • 其他情况下,最大延迟 0.5s 发送 ACK(很多操作系统设置为 0.2s 左右)

二、UDP

UDP(User Datagram Protocol),用户数据报协议,目标是在传输层提供直接发送报文(Datagram)的能力,不帮助拆分数据,Datagram 就是数据传输的最小单位,也不提供复杂的控制协议,利用 IP 提供面向无连接的通信服务。即使是出现网络拥堵的情况下,UDP 也无法进行流量控制等避免网络拥塞的行为。此外,传输途中即使出现丢包,UDP 也不负责重发。甚至当出现包的到达顺序乱掉时也没有纠正的功能。如果需要这些细节控制,那么不得不交由采用 UDP 的应用程序去处理。

UDP 不提供可靠性,不代表我们不能解决可靠性。UDP 的核心价值是灵活、轻量,构造了最小版本的传输层协议。在这个之上,还可以实现连接(Connection),实现会话(Session),实现可靠性(Relaability)等。所以理论上,任何一个用 TCP 协议构造的成熟应用层协议,都可以用 UDP 重构。

UDP 是一种没有复杂控制,提供面向无连接通信服务的一种协议。换句话说,它将部分控制转移给应用程序去处理,自己却只提供作为传输层协议的最基本功能,本身处理既简单又高效,因此经常用于以下几个方面:

  • 包总量较少的通信(DNS、PING、SNMP 等)
  • 视频、音频等多媒体通信(即时通信)
  • 限定于 LAN 等特定网络中的应用通信
  • 广播通信(广播、多播)

三、总结

TCP 和 UCP 比较可以从以下几个方面着手:可靠性差异、连接vs无连接、流控技术(拥塞控制)、传输速度、应用场景差异。

TCP 是一种面向有连接的传输层协议。它可以保证两端通信主机之间的通信可达。TCP 能够正确处理在传输过程中丢包、传输顺序乱掉等异常情况。此外,TCP 还能够有效利用带宽,缓解网络拥堵。然而,为了建立与断开连接,有时它需要至少 7 次的发包丢包,导致网络流量的浪费。此外,为了提高网络的利用率,TCP 协议中定义了各种各样复杂的规范,因此不利于视频会议(音频、视频的数据量既定)等场合使用。

UDP 有别于 TCP,它是一种面向无连接的传输层协议。UDP 不会关注对端是否真的收到了传送过去的数据,如果需要检查对端是否收到分组数据包,或者对端是否连接到网络,则需要在应用程序中实现。UDP 常用于分组数据较少或多播、广播通信以及视频通信等多媒体领域。

TCP 相比 UDP 需要消耗更多的资源,比如必须先协商建立连接、每次 PSH 消息都需要 ACK 等。

近些年有一个趋势,TCP/UDP 的边界逐渐变得模糊,UDP 应用越来越多。比如传输文件,如果考虑希望文件无损到达,可以用 TCP。如果考虑希望传输足够快,就可能会用 UDP。再比如 HTTP 协议,如果考虑请求/返回的可靠性,用 TCP 比较合适。但是像 HTTP 3.0 这类应用层协议,从功能性上思考,暂时没有找到太多的优化点,但是想要把网络优化到极致,就会用 UDP 作为底层技术,然后在 UDP 基础上解决可靠性。

posted @ 2021-04-14 19:07  JMCui  阅读(993)  评论(1编辑  收藏  举报