TCP和UDP的介绍及使用场景

TCP和UDP的优势和劣势

TCP 最核心的价值是提供了可靠性,而 UDP 最核心的价值是灵活,你几乎可以用它来做任何事情。

例如:HTTP 协议 1.1 和 2.0 都基于 TCP,而到了 HTTP 3.0 就开始用 UDP 了。

TCP 的稳定性

TCP 作为一个传输层协议,最核心的能力是传输。传输需要保证可靠性,还需要控制流速,这两个核心能力均由滑动窗口提供

请求/响应模型

TCP 中每个发送的请求都需要响应。如果一个请求没有收到响应,发送方就会认为这次发送出现了故障,会触发重发。

排队(Queuing)

TCP和UDP的介绍及使用场景_第1张图片

滑动窗口(Sliding Window)

TCP和UDP的介绍及使用场景_第2张图片

如上图所示:

  • 深绿色代表已经收到 ACK 的段
  • 浅绿色代表发送了,但是没有收到 ACK 的段
  • 白色代表没有发送的段
  • 紫色代表暂时不能发送的段

将已发送的数据放到最左边,发送中的数据放到中间,未发送的数据放到右边。

假设我们最多同时发送 5 个封包,也就是窗口大小 = 5。窗口中的数据被同时发送出去,然后等待 ACK。如果一个封包 ACK 到达,我们就将它标记为已接收(深绿色)。

如下图所示,有两个封包的 ACK 到达,因此标记为绿色。

TCP和UDP的介绍及使用场景_第3张图片

这个时候滑动窗口可以向右滑动,如下图所示:

TCP和UDP的介绍及使用场景_第4张图片

重传

如果发送过程中,部分数据没能收到 ACK 会怎样呢?这就可能发生重传。

如果发生下图这样的情况,段 4 迟迟没有收到 ACK。

TCP和UDP的介绍及使用场景_第5张图片

这个时候滑动窗口只能右移一个位置,如下图所示:
TCP和UDP的介绍及使用场景_第6张图片

在这个过程中,如果后来段 4 重传成功(接收到 ACK),那么窗口就会继续右移。

如果段 4 发送失败,还是没能收到 ACK,那么接收方也会抛弃段 5、段 6、段 7。

这样从段 4 开始之后的数据都需要重发。

快速重传

在 TCP 协议中,如果接收方想丢弃某个段,可以选择不发 ACK。

发送端超时后,会重发这个 TCP 段。而有时候,接收方希望催促发送方尽快补发某个 TCP 段,这个时候可以使用快速重传能力。

例如段 1、段 2、段 4 到了,但是段 3 没有到。 接收方可以发送多次段 3 的 ACK。如果发送方收到多个段 3 的 ACK,就会重发段 3。这个机制称为快速重传。这和超时重发不同,是一种催促的机制。

为了不让发送方误以为段 3 已经收到了,在快速重传的情况下,接收方即便收到发来的段 4,依然会发段 3 的 ACK(不发段 4 的 ACK),直到发送方把段 3 重传。

思考:窗口大小的单位是?

在上面所有的图片中,窗口大小是 TCP 段的数量。

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

流速控制

发送、接收窗口的大小可以用来控制 TCP 协议的流速。

窗口越大,同时可以发送、接收的数据就越多,支持的吞吐量也就越大。

当然,窗口越大,如果数据发生错误,损失也就越大,因为需要重传越多的数据。

举个例子:我们用 RTT 表示 Round Trip Time,就是消息一去一回的时间。

假设 RTT = 1ms,带宽是 1mb/s。

如果窗口大小为 1kb,那么 1ms 可以发送一个 1kb 的数据(含 TCP 头),1s 就可以发送 1mb 的数据,刚好可以将带宽用满。

如果 RTT 再慢一些,比如 RTT = 10ms,那么这样的设计就只能用完 1/10 的带宽。 当然你可以提高窗口大小提高吞吐量,但是实际的模型会比这个复杂,因为还存在重传、快速重传、丢包等因素。

而实际操作中,也不可以真的把带宽用完,所以最终我们会使用折中的方案,在延迟、丢包率、吞吐量中进行选择。

滑动窗口是 TCP 协议控制可靠性的核心。发送方将数据拆包,变成多个分组。然后将数据放入一个拥有滑动窗口的数组,依次发出,仍然遵循先入先出(FIFO)的顺序,但是窗口中的分组会一次性发送。窗口中序号最小的分组如果收到 ACK,窗口就会发生滑动;如果最小序号的分组长时间没有收到 ACK,就会触发整个窗口的数据重新发送。另一方面,在多次传输中,网络的平均延迟往往是相对固定的,这样 TCP 协议可以通过双方协商窗口大小控制流速。

既然发送方有窗口,那么接收方也需要有窗口吗

接收方收到发送方的每个数据分组(或者称为 TCP Segment),接收方肯定需要缓存。

举例来说,如果发送方发送了:1, 2, 3, 4。 那么接收方可能收到的一种情况是:1,4,3。注意,没有收到 2 的原因可能是延迟、丢包等。这个时候,接收方有两种选择。

选择一:什么都不做(这样分组 2 的 ACK 就不会发送给发送方,发送方发现没有收到 2 的 ACK,过一段时间就有可能重发 2,3,4,5)。 当然具体设计还需要探讨,比如不重发整个分组,只重发已发送没有收到 ACK 的分组。

这种方法的缺陷是性能太差,重发了整个分组(或部分)。因此我们可以考虑另一种选择。

选择二:如果重发一个窗口,或部分窗口,问题就不会太大了。虽然增加了网络开销,但是毕竟有进步(1 进步了,不会再重发)。

性能方面最大的开销是等待超时的时间,就是发送方要等到超时时间才重发窗口,这样操作性能太差。

因此,TCP 协议有一个快速重传的机制——接收方发现接收到了 1,但是没有接收到 2,那么马上发送 3 个分组 2 的 ACK 给到发送方,这样发送方收到多个 ACK,就知道接收方没有收到 2,于是马上重发 2。

无论是上面哪种方案,接收方也维护一个滑动窗口,是一个不错的选择。接收窗口的状态,可以和发送窗口的状态相互对应了。

当接收方给发送方回复ack的时候会携带接收方窗口大小,发送方就会根据这个回复来动态调整自己的窗口大小。。双方协商,就是带上窗口大小。窗口大小通常是接收方说了算。

UDP 协议

UDP(User Datagram Protocol),目标是在传输层提供直接发送报文(Datagram)的能力。

为什么不直接调用 IP 协议呢? 如果裸发数据,IP 协议不香吗?

这是因为传输层协议在承接上方应用层的调用,需要提供应用到应用的通信——因此要附上端口号。每个端口,代表不同的应用。传输层下层的 IP 协议,承接传输层的调用,将数据从主机传输到主机。IP 层不能区分应用,导致哪怕是在 IP 协议上进行简单封装,也需要单独一个协议。这就构成了 UDP 协议的市场空间。

UDP 的封包格式

UDP 的设计目标就是在允许用户直接发送报文的情况下,最大限度地简化应用的设计。

UDP 的报文格式

TCP和UDP的介绍及使用场景_第7张图片

UDP 的报文非常简化,只有 5 个部分。

  • Source Port 是源端口号。因为 UDP 协议的特性(不需要 ACK),因此这个字段是可以省略的。但有时候对于防火墙、代理来说,Source Port 有很重要的意义,它们需要用这个字段行过滤和路由。
  • Destination Port 是目标端口号(这个字段不可以省略)。
  • Length 是消息体长度
  • Checksum 是校验和,作用是检查封包是否出错。
  • Data octets 就是一个字节一个字节的数据,Octet 是 8 位。

校验和(Checksum)机制,这个机制在很多的网络协议中都会存在,因为校验数据在传输过程中有没有丢失、损坏是一个普遍需求。

比如现在数据有 4 个 byte:a,b,c,d,那么一种最简单的校验和就是:checksum=(a+b+c+d) ^ 0xff

如果发送方用上述方式计算出 Checksum,并将 a,b,c,d 和 Checksum 一起发送给接收方,接收方就可以用同样的算法再计算一遍,这样就可以确定数据有没有发生损坏变化)。

当然 Checksum 的做法,只适用于数据发生少量变化的情况。如果数据发生较大的变动,校验和也可能发生碰撞。

你可以看到 UDP 的可靠性保证仅仅就是 Checksum 一种。

如果一个数据封包 Datagram 发生了数据损坏,UDP 可以通过 Checksum 纠错或者修复。

但是 UDP 没有提供再多的任何机制,比如 ACK、顺序保证以及流控等。

UDP 与 TCP的区别

1. 目的差异

首先,这两个协议的目的不同:

  • TCP 协议的核心目标是提供可靠的网络传输

  • UDP 的目标是在提供报文交换能力基础上尽可能地简化协议轻装上阵

2. 可靠性差异
  • TCP 核心是要在保证可靠性提供更好的服务。TCP 会有握手的过程,需要建立连接,保证双方同时在线。而且TCP 有时间窗口持续收集无序的数据,直到这一批数据都可以合理地排序组成连续的结果。

  • UDP 并不具备以上这些特性,它只管发送数据封包,而且 UDP 不需要 ACK,这意味着消息发送出去成功与否 UDP 是不管的。

3. 连接 vs 无连接
  • TCP 是一个面向连接的协议(Connection-oriented Protocol),传输数据必须先建立连接。
  • UDP 是一个无连接协议(Connection-less Protocol),数据随时都可以发送,只提供发送封包(Datagram)的能力。
4. 流控技术(Flow Control)
  • TCP 使用了流控技术确保发送方不会因为一次发送过多的数据包而使接收方不堪重负。TCP 在发送缓冲区中存储数据,并在接收缓冲区中接收数据。当应用程序准备就绪时,它将从接收缓冲区读取数据。如果接收缓冲区已满,接收方将无法处理更多数据,并将其丢弃。
  • UDP 没有提供类似的能力。
5. 传输速度
  • UDP 协议简化,封包小,没有连接、可靠性检查等,因此单纯从传输速度上讲,UDP 更快
6. 场景差异

TCP 每个数据封包都需要确认,因此天然不适应高速数据传输场景,比如观看视频(流媒体应用)、网络游戏(TCP 有延迟)等。具体来说,

如果网络游戏用 TCP,每个封包都需要确认,可能会造成一定的延迟;再比如音、视频传输天生就允许一定的丢包率;

Ping 和 DNS Lookup,这类型的操作只需要一次简单的请求/返回,不需要建立连接,用 UDP 就足够了。

ping (Packet Internet Groper):因特网包探索器,用于测试网络连接量的程序

DNS Lookup(域名解析):请求某域名下的资源,浏览器需要先通过DNS解析器得到该域名服务器的IP地址。在DNS查找完成之前,浏览器不能从主机名那里下载到任何东西。

如果考虑希望传输足够块,就可能会用 UDP。

再比如 HTTP 协议,如果考虑请求/返回的可靠性,用 TCP 比较合适。

但是像 HTTP 3.0 这类应用层协议,从功能性上思考,暂时没有找到太多的优化点,但是想要把网络优化到极致,就会用 UDP 作为底层技术,然后在 UDP 基础上解决可靠性。

所以理论上,任何一个用 TCP 协议构造的成熟应用层协议,都可以用 UDP 重构

第一类:TCP 场景

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

第二类:UDP 场景

  • 网络游戏
  • 音视频传输
  • DNS
  • Ping
  • 直播

第三类:模糊地带(TCP、UDP 都可以考虑)

  • HTTP(目前以 TCP 为主)
  • 文件传输

总结

  • UDP 的核心价值是灵活、轻量,构造了最小版本的传输层协议。
  • TCP 最核心的价值就是提供封装好的一套解决可靠性的优秀方案

解决可靠性是非常复杂的,要考虑非常多的因素。

  • TCP 帮助我们在确保吞吐量、延迟、丢包率的基础上,保证可靠性。

  • UDP 则不同,UDP 提供了最小版的实现,只支持 ChecksumUDP 最核心的价值是灵活、轻量、传输速度快

  • 最后还有一个非常重要的考虑因素就是成本,如果没有足够专业的团队解决网络问题,TCP 无疑会是更好的选择。

Moba 类多人竞技游戏的网络应该用 TCP 还是 UDP**?

Moba类游戏的传输协议是基于UDP的封装。首先Moba类游戏一般对实时性有要求,如果使用了TCP,再怎么优化也受TCP连接效率的影响。而UDP传输效率相对来说较高,但可靠性欠佳。因此思路应该是基于UDP协议做一些优化,牺牲部分的传输效率,保证其可靠性,但是又不需要像TCP协议那样有一套完善的机制来保证其可靠性。

文章参考《计算机网络通关 29 讲》—— 林䭽

你可能感兴趣的:(计算机网络,tcpip,udp,计算机网络)