43 张图带你搞懂 TCP 和 UDP(四)

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 这一篇文章是计算机网络连载文章的第四篇,历史文章请阅读 拿下计网协议后,我就是公园里最靓的仔 TCP/IP 基础知识总结 计算机网络基础知识总结 那么下面就开始我们本篇文章,文章组织脉络如下

传输控制

利用窗口控制提高速度

前面我们介绍了 TCP 是以数据段的形式进行发送,如果经过一段时间内主机 A 等不到主机 B 的响应,主机 A 就会重新发送报文段,接受到主机 B 的响应,再会继续发送后面的报文段,我们现在看到,这一问一答的形式还存在许多条件,比如响应未收到、等待响应等,那么对崇尚性能的互联网来说,这种形式的性能应该不会很高。

微信图片_20220416141934.png

那么如何提升性能呢?

为了解决这个问题,TCP 引入了 窗口 这个概念,即使在往返时间较长、频次很多的情况下,它也能控制网络性能的下降,听起来很牛批,那它是如何实现的呢?

如下图所示

微信图片_20220416141938.png

我们之前每次请求发送都是以报文段的形式进行的,引入窗口后,每次请求都可以发送多个报文段,也就是说一个窗口可以发送多个报文段。窗口大小就是指无需等待确认应答就可以继续发送报文段的最大值。

在这个窗口机制中,大量使用了 缓冲区 ,通过对多个段同时进行确认应答的功能。

如下图所示,发送报文段中高亮部分即是我们提到的窗口,在窗口内,即使没有收到确认应答也可以把请求发送出去。不过,在整个窗口的确认应答没有到达之前,如果部分报文段丢失,那么主机 A 将仍会重传。为此,主机 A 需要设置缓存来保留这些需要重传的报文段,直到收到他们的确认应答。

微信图片_20220416141942.png

在滑动窗口以外的部分是尚未发送的报文段和已经接受到的报文段,如果报文段已经收到确认则不可进行重发,此时报文段就可以从缓冲区中清除。

在收到确认的情况下,会将窗口滑动到确认应答中确认号的位置,如上图所示,这样可以顺序的将多个段同时发送,用以提高通信性能,这种窗口也叫做 滑动窗口(Sliding window)

窗口控制和重发

报文段的发送和接收,必然伴随着报文段的丢失和重发,窗口也是同样如此,如果在窗口中报文段发送过程中出现丢失怎么办?

首先我们先考虑确认应答没有返回的情况。在这种情况下,主机 A 发送的报文段到达主机 B,是不需要再进行重发的。这和单个报文段的发送不一样,如果发送单个报文段,即使确认应答没有返回,也要进行重发

微信图片_20220416141949.png

窗口在一定程度上比较大时,即使有少部分确认应答的丢失,也不会重新发送报文段。

我们知道,如果在某个情况下由于发送的报文段丢失,导致接受主机未收到请求,或者主机返回的响应未到达客户端的话,会经过一段时间重传报文。那么在使用窗口的情况下,报文段丢失会怎么样呢?

如下图所示,报文段 0 - 999 丢失后,但是主机 A 并不会等待,主机 A 会继续发送余下的报文段,主机 B 发送的确认应答却一直是 1000,同一个确认号的应答报文会被持续不断的返回,如果发送端主机在连续 3 次收到同一个确认应答后,就会将其所对应的数据重发,这种机制要比之前提到的超时重发更加高效,这种机制也被称为 高速重发控制。这种重发的确认应答也被称为 冗余 ACK(响应)

微信图片_20220416141954.png

主机 B 在没有接收到自己期望序列号的报文段时,会对之前收到的数据进行确认应答。发送端则一旦收到某个确认应答后,又连续三次收到同样的确认应答,那么就会认为报文段已经丢失。需要进行重发。使用这种机制可以提供更为快速的重发服务

流量控制

前面聊的是传输控制,下面 cxuan 再和你聊一下 流量控制。我们知道,在每个 TCP 连接的一侧主机都会有一个 socket 缓冲区,缓冲区会为每个连接设置接收缓存和发送缓存,当 TCP 建立连接后,从应用程序产生的数据就会到达接收方的接收缓冲区中,接收方的应用程序并不一定会马上读取缓冲区的数据,它需要等待操作系统分配时间片。如果此时发送方的应用程序产生数据过快,而接收方读取接受缓冲区的数据相对较慢的话,那么接收方中缓冲区的数据将会溢出

但是还好,TCP 有 流量控制服务(flow-control service) 用于消除缓冲区溢出的情况。流量控制是一个速度匹配服务,即发送方的发送速率与接受方应用程序的读取速率相匹配。

TCP 通过使用一个 接收窗口(receive window) 的变量来提供流量控制。接受窗口会给发送方一个指示到底还有多少可用的缓存空间。发送端会根据接收端的实际接受能力来控制发送的数据量。

接收端主机向发送端主机通知自己可以接收数据的大小,发送端会发送不超过这个限度的数据,这个大小限度就是窗口大小,还记得 TCP 的首部么,有一个接收窗口,我们上面聊的时候说这个字段用于流量控制。它用于指示接收方能够/愿意接受的字节数量。

那么只知道这个字段用于流量控制,那么如何控制呢?

发送端主机会定期发送一个窗口探测包,这个包用于探测接收端主机是否还能够接受数据,当接收端的缓冲区一旦面临数据溢出的风险时,窗口大小的值也随之被设置为一个更小的值通知发送端,从而控制数据发送量。

下面是一个流量控制示意图

微信图片_20220416141958.png

发送端主机根据接收端主机的窗口大小进行流量控制。由此也可以防止发送端主机一次发送过大数据导致接收端主机无法处理。

如上图所示,当主机 B 收到报文段 2000 - 2999 之后缓冲区已满,不得不暂时停止接收数据。然后主机 A 发送窗口探测包,窗口探测包非常小仅仅一个字节。然后主机 B 更新缓冲区接收窗口大小并发送窗口更新通知给主机 A,然后主机 A 再继续发送报文段。

在上面的发送过程中,窗口更新通知可能会丢失,一旦丢失发送端就不会发送数据,所以窗口探测包会随机发送,以避免这种情况发生。

连接管理

在继续介绍下面有意思的特性之前,我们先来把关注点放在 TCP 的连接管理上,因为没有 TCP 连接,也就没有后续的一系列 TCP 特性什么事儿了。假设运行在一台主机上的进程想要和另一台主机上的进程建立一条 TCP 连接,那么客户中的 TCP 会使用下面这些步骤与服务器中的 TCP 建立连接。

  • 首先,客户端首先向服务器发送一个特殊的 TCP 报文段。这个报文段首部不包含应用层数据,但是在报文段的首部中有一个 SYN 标志位 被置为 1。因此,这个特殊的报文段也可以叫做 SYN 报文段。然后,客户端随机选择一个初始序列号(client_isn) ,并将此数字放入初始 TCP SYN 段的序列号字段中,SYN 段又被封装在 IP 数据段中发送给服务器。
  • 一旦包含 IP 数据段到达服务器后,服务端会从 IP 数据段中提取 TCP SYN 段,将 TCP 缓冲区和变量分配给连接,然后给客户端发送一个连接所允许的报文段。这个连接所允许的报文段也不包括任何应用层数据。然而,它却包含了三个非常重要的信息。

这些缓冲区和变量的分配使 TCP 容易受到称为 SYN 泛洪的拒绝服务攻击。

  • 首先,SYN 比特被置为 1 。
  • 然后,TCP 报文段的首部确认号被设置为 client_isn + 1
  • 最后,服务器选择自己的初始序号(server_isn),并将其放置到 TCP 报文段首部的序号字段中。
    如果用大白话解释下就是,我收到了你发起建立连接的 SYN 报文段,这个报文段具有首部字段 client_isn。我同意建立该连接,我自己的初始序号是 server_isn。这个允许连接的报文段被称为 SYNACK 报文段
  • 第三步,在收到 SYNACK 报文段后,客户端也要为该连接分配缓冲区和变量。客户端主机向服务器发送另外一个报文段,最后一个报文段对服务器发送的响应报文做了确认,确认的标准是客户端发送的数据段中确认号为 server_isn + 1,因为连接已经建立,所以 SYN 比特被置为 0 。以上就是 TCP 建立连接的三次数据段发送过程,也被称为 三次握手

一旦完成这三个步骤,客户和服务器主机就可以相互发送报文段了,在以后的每一个报文段中,SYN 比特都被置为 0 ,整个过程描述如下图所示

微信图片_20220416142004.png

在客户端主机和服务端主机建立连接后,参与一条 TCP 连接的两个进程中的任何一个都能终止 TCP 连接。连接结束后,主机中的缓存和变量将会被释放。假设客户端主机想要终止 TCP 连接,它会经历如下过程

客户应用进程发出一个关闭命令,客户 TCP 向服务器进程发送一个特殊的 TCP 报文段,这个特殊的报文段的首部标志 FIN 被设置为 1 。当服务器收到这个报文段后,就会向发送方发送一个确认报文段。然后,服务器发送它自己的终止报文段,FIN 位被设置为 1 。客户端对这个终止报文段进行确认。此时,在两台主机上用于该连接的所有资源都被释放了,如下图所示

微信图片_20220416142007.png

在一个 TCP 连接的生命周期内,运行在每台主机中的 TCP 协议都会在各种 TCP 状态(TCP State) 之间进行变化,TCP 的状态主要有 LISTEN、SYN-SEND、SYN-RECEIVED、ESTABLISHED、FIN-WAIT-1、FIN-WAIT-2、CLOSE-WAIT、CLOSING、LAST-ACK、TIME-WAIT 和 CLOSED 。这些状态的解释如下

  • LISTEN: 表示等待任何来自远程 TCP 和端口的连接请求。
  • SYN-SEND: 表示发送连接请求后等待匹配的连接请求。
  • SYN-RECEIVED: 表示已接收并发送连接请求后等待连接确认,也就是 TCP 三次握手中第二步后服务端的状态
  • ESTABLISHED: 表示已经连接已经建立,可以将应用数据发送给其他主机

上面这四种状态是 TCP 三次握手所涉及的。

  • FIN-WAIT-1: 表示等待来自远程 TCP 的连接终止请求,或者等待先前发送的连接终止请求的确认。
  • FIN-WAIT-2: 表示等待来自远程 TCP 的连接终止请求。
  • CLOSE-WAIT: 表示等待本地用户的连接终止请求。
  • CLOSING: 表示等待来自远程 TCP 的连接终止请求确认。
  • LAST-ACK: 表示等待先前发送给远程 TCP 的连接终止请求的确认(包括对它的连接终止请求的确认)。
  • TIME-WAIT: 表示等待足够的时间以确保远程 TCP 收到其连接终止请求的确认。
  • CLOSED: 表示连接已经关闭,无连接状态。

上面 7 种状态是 TCP 四次挥手,也就是断开链接所设计的。

TCP 的连接状态会进行各种切换,这些 TCP 连接的切换是根据事件进行的,这些事件由用户调用:OPEN、SEND、RECEIVE、CLOSE、ABORT 和 STATUS。涉及到 TCP 报文段的标志有 SYN、ACK、RST 和 FIN ,当然,还有超时。

我们下面加上 TCP 连接状态后,再来看一下三次握手和四次挥手的过程。

三次握手建立连接

下图画出了 TCP 连接建立的过程。假设图中左端是客户端主机,右端是服务端主机,一开始,两端都处于CLOSED(关闭)状态。

微信图片_20220416142011.png

  1. 服务端进程准备好接收来自外部的 TCP 连接,一般情况下是调用 bind、listen、socket 三个函数完成。这种打开方式被认为是 被动打开(passive open)。然后服务端进程处于 LISTEN 状态,等待客户端连接请求。
  2. 客户端通过 connect 发起主动打开(active open),向服务器发出连接请求,请求中首部同步位 SYN = 1,同时选择一个初始序号 sequence ,简写 seq = x。SYN 报文段不允许携带数据,只消耗一个序号。此时,客户端进入 SYN-SEND 状态。
  3. 服务器收到客户端连接后,,需要确认客户端的报文段。在确认报文段中,把 SYN 和 ACK 位都置为 1 。确认号是 ack = x + 1,同时也为自己选择一个初始序号 seq = y。请注意,这个报文段也不能携带数据,但同样要消耗掉一个序号。此时,TCP 服务器进入 SYN-RECEIVED(同步收到) 状态。
  4. 客户端在收到服务器发出的响应后,还需要给出确认连接。确认连接中的 ACK 置为 1 ,序号为 seq = x + 1,确认号为 ack = y + 1。TCP 规定,这个报文段可以携带数据也可以不携带数据,如果不携带数据,那么下一个数据报文段的序号仍是 seq = x + 1。这时,客户端进入 ESTABLISHED (已连接) 状态
  5. 服务器收到客户的确认后,也进入 ESTABLISHED 状态。

TCP 建立一个连接需要三个报文段,释放一个连接却需要四个报文段。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
18天前
|
网络协议 算法 网络性能优化
|
6天前
|
网络协议 SEO
TCP连接管理与UDP协议IP协议与ethernet协议
TCP、UDP、IP和Ethernet协议是网络通信的基石,各自负责不同的功能和层次。TCP通过三次握手和四次挥手实现可靠的连接管理,适用于需要数据完整性的场景;UDP提供不可靠的传输服务,适用于低延迟要求的实时通信;IP协议负责数据包的寻址和路由,是网络层的重要协议;Ethernet协议定义了局域网的数据帧传输方式,广泛应用于局域网设备之间的通信。理解这些协议的工作原理和应用场景,有助于设计和维护高效可靠的网络系统。
17 4
|
12天前
|
缓存 负载均衡 网络协议
面试:TCP、UDP如何解决丢包问题
TCP、UDP如何解决丢包问题。TCP:基于数据块传输/数据分片、对失序数据包重新排序以及去重、流量控制(滑动窗口)、拥塞控制、自主重传ARQ;UDP:程序执行后马上开始监听、控制报文大小、每个分割块的长度小于MTU
|
28天前
|
网络协议 前端开发 物联网
TCP和UDP区别?
本文首发于微信公众号“前端徐徐”,详细介绍了TCP和UDP两种传输层协议的核心概念、连接性和握手过程、数据传输和可靠性、延迟和效率、应用场景及头部开销。TCP面向连接、可靠、有序,适用于网页浏览、文件传输等;UDP无连接、低延迟、高效,适用于实时音视频传输、在线游戏等。
39 1
TCP和UDP区别?
|
20天前
|
Web App开发 缓存 网络协议
不为人知的网络编程(十八):UDP比TCP高效?还真不一定!
熟悉网络编程的(尤其搞实时音视频聊天技术的)同学们都有个约定俗成的主观论调,一提起UDP和TCP,马上想到的是UDP没有TCP可靠,但UDP肯定比TCP高效。说到UDP比TCP高效,理由是什么呢?事实真是这样吗?跟着本文咱们一探究竟!
46 10
|
30天前
|
网络协议 网络性能优化 C#
C# 一分钟浅谈:UDP 与 TCP 协议区别
【10月更文挑战第8天】在网络编程中,传输层协议的选择对应用程序的性能和可靠性至关重要。本文介绍了 TCP 和 UDP 两种常用协议的基础概念、区别及应用场景,并通过 C# 代码示例详细说明了如何处理常见的问题和易错点。TCP 适用于需要可靠传输和顺序保证的场景,而 UDP 适用于对延迟敏感且可以容忍一定数据丢失的实时应用。
28 1
|
1月前
|
网络协议 Linux 网络性能优化
Linux C/C++之TCP / UDP通信
这篇文章详细介绍了Linux下C/C++语言实现TCP和UDP通信的方法,包括网络基础、通信模型、编程示例以及TCP和UDP的优缺点比较。
35 0
Linux C/C++之TCP / UDP通信
|
1月前
|
网络协议 算法 数据格式
【TCP/IP】UDP协议数据格式和报文格式
【TCP/IP】UDP协议数据格式和报文格式
113 3
|
1月前
|
存储 网络协议 Java
【网络】UDP和TCP之间的差别和回显服务器
【网络】UDP和TCP之间的差别和回显服务器
65 1
|
1月前
|
网络协议 网络性能优化
详解TCP/IP协议以及UDP
详解TCP/IP协议以及UDP
41 0