40 张图带你搞懂 TCP 和 UDP,android软件开发教程

  • ,采用 UDP 协议时,只要应用进程将数据传给 UDP,UDP 就会将此数据打包进 UDP 文段并立刻传递给 络层,然后 TCP 有拥塞控制的功能,它会在发送前判断互联 的拥堵情况,如果互联 极度阻塞,那么就会抑制 TCP 的发送方。使用 UDP 的目的就是希望实时性。

  • ,TCP 在数据传输之前需要经过三次握手的操作,而 UDP 则无须任何准备即可进行数据传输。因此 UDP 没有建立连接的时延。如果使用 TCP 和 UDP 来比喻开发人员:TCP 就是那种凡事都要设计好,没设计不会进行开发的工程师,需要把一切因素考虑在内后再开干!所以非常;而 UDP 就是那种上来直接干干干,接到项目需求马上就开干,也不管设计,也不管技术选型,就是干,这种开发人员非常,但是适合快速迭代开发,因为可以马上上手!

  • ,TCP 需要在端系统中维护,连接状态包括接收和发送缓存、拥塞控制参数以及序 和确认 的参数,在 UDP 中没有这些参数,也没有发送缓存和接受缓存。因此,某些专门用于某种特定应用的服务器当应用程序运行在 UDP 上,一般能支持更多的活跃用户

  • ,每个 TCP 文段都有 20 字节的首部开销,而 UDP 仅仅只有 8 字节的开销。

这里需要注意一点,并不是所有使用 UDP 协议的应用层都是的,应用程序可以自己实现可靠的数据传输,通过增加确认和重传机制。所以使用 UDP 协议最大的特点就是速度快。

UDP 文结构

下面来一起看一下 UDP 的 文结构,每个 UDP 文分为 UDP 头和 UDP 数据区两部分。 头由 4 个 16 位长(2 字节)字段组成,分别说明该 文的源端口、目的端口、 文长度和校验值。

? 这些 16 比特的前两个和是

最后一次相加的位会进行溢出,溢出位 1 要被舍弃,然后进行反码运算,反码运算就是将所有的 1 变为 0 ,0 变为 1。因此 1000 0100 1001 0101 的反码就是 0111 1011 0110 1010,这就是校验和,如果在接收方,数据没有出现差错,那么全部的 4 个 16 比特的数值进行运算,同时也包括校验和,如果最后结果的值不是 1111 1111 1111 1111 的话,那么就表示传输过程中的数据出现了差错。

下面来想一个问题,为什么 UDP 会提供差错检测的功能p>

这其实是一种 的设计原则,这个原则说的是要让传输中各种错误发生的概率降低到一个可以接受的水平

文件从主机_A_传到主机_B_,也就是说_AB_主机要通信,需要经过三个环节:首先是主机_A_从磁盘上读取文件并将数据分组成一个个数据包_packet,,然后数据包通过连接主机_A_和主机_B_的 络传输到主机_B,最后是主机_B_收到数据包并将数据包写入磁盘。在这个看似简单其实很复杂的过程中可能会由于某些原因而影响正常通信。比如:磁盘上文件读写错误、缓冲溢出、内存出错、 络拥挤等等这些因素都有可能导致数据包的出错或者丢失,由此可见用于通信的 络是不可靠的。

由于实现通信只要经过上述三个环节,那么我们就想是否在其中某个环节上增加一个检错纠错机制来用于对信息进行把关呢p>

络层肯定不能做这件事,因为 络层的最主要目的是增大数据传输的速率, 络层不需要考虑数据的完整性,数据的完整性和正确性交给端系统去检测就行了,因此在数据传输中,对于 络层只能要求其提供尽可能好的数据传输服务,而不可能寄希望于 络层提供数据完整性的服务。

UDP 不可靠的原因是它虽然提供差错检测的功能,但是对于差错没有恢复能力更不会有重传机制

TCP


UDP 是一种没有复杂的控制,提供无连接通信服务的一种协议,换句话说,它将部分控制部分交给应用程序去处理,自己只提供作为传输层协议最基本的功能。

而与 UDP 不同的是,同样作为传输层协议,TCP 协议要比 UDP 的功能多很多。

的全称是 ,它被称为是一种 的协议,这是因为一个应用程序开始向另一个应用程序发送数据之前,这两个进程必须先进行,握手是一个逻辑连接,并不是两个主机之间进行真实的握手。

TCP 的连接建立需要经过三次握手,这个我们下面再说。一旦 TCP 连接建立后,主机之间就可以相互发送数据了,客户进程通过套接字传送数据流。数据一旦通过套接字后,它就由客户中运行的 TCP 协议所控制。

TCP 会将数据临时存储到连接的 中,这个 send buffer 是三次握手之间设置的缓存之一,然后 TCP 在合适的时间将发送缓存中的数据发送到目标主机的接收缓存中,实际上,每一端都会有发送缓存和接收缓存,如下所示

TCP 文段结构相比 UDP 文结构多了很多内容。但是前两个 32 比特的字段是一样的。它们是 和 ,我们知道,这两个字段是用于多路复用和多路分解的。另外,和 UDP 一样,TCP 也包含 ,除此之外,TCP 文段首部还有下面这些

  • 32 比特的 和 32 比特的 。这些字段被 TCP 发送方和接收方用来实现可靠的数据传输。

  • 4 比特的,这个字段指示了以 32 比特的字为单位的 TCP 首部长度。TCP 首部的长度是可变的,但是通常情况下,选项字段为空,所以 TCP 首部字段的长度是 20 字节。

  • 16 比特的 ,这个字段用于流量控制。它用于指示接收方能够/愿意接受的字节数量

  • 可变的,这个字段用于发送方和接收方协商最大 文长度,也就是 MSS 时使用

  • 6 比特的 , 标志用于指示确认字段中的值是有效的,这个 文段包括一个对已被成功接收 文段的确认;、、 标志用于连接的建立和关闭; 和 用于拥塞控制; 标志用于表示立刻将数据交给上层处理; 标志用来表示数据中存在需要被上层处理的 紧急 数据。紧急数据最后一个字节由 16 比特的 指出。一般情况下,PSH 和 URG 并没有使用。

TCP 的各种功能和特点都是通过 TCP 文结构来体现的,在聊完 TCP 文结构之后,我们下面就来聊一下 TCP 有哪些功能及其特点了。

序 、确认 实现传输可靠性

TCP 文段首部中两个最重要的字段就是 和 ,这两个字段是 TCP 实现可靠性的基础,那么你肯定好奇如何实现可靠性呢解这一点,首先我们得先知道这两个字段里面存了哪些内容吧p>

一个 文段的序 就是数据流的字节编 。因为 TCP 会把数据流分割成为一段一段的字节流,因为字节流本身是有序的,所以每一段的字节编 就是标示是哪一段的字节流。比如,主机 A 要给主机 B 发送一条数据。数据经过应用层产生后会有一串数据流,数据流会经过 TCP 分割,分割的依据就是 MSS,假设数据是 10000 字节,MSS 是 2000 字节,那么 TCP 就会把数据拆分成 0 – 1999 , 2000 – 3999 的段,依次类推。

所以,第一个数据 0 – 1999 的首字节编 就是 0 ,2000 – 3999 的首字节编 就是 2000 。。。。。。

然后,每个序 都会被填入 TCP 文段首部的序 字段中。

TCP 是一种全双工的通信协议,因此主机 A 在向主机 B 发送消息的过程中,也在接受来自主机 B 的数据。主机 A 填充进 文段的确认 是期望从主机 B 收到的下一字节的序 。稍微有点绕,我们来举个例子看一下。比如主机 A 收到了来自主机 B 发送的编 为 0 – 999 字节的 文段,这个 文段会写入序 中,随后主机 A 期望能够从主机 B 收到 1000 – 剩下的 文段,因此,主机 A 发送到主机 B 的 文段中,它的确认 就是 1000 。

累积确认

这里再举出一个例子,比如主机 A 在发送 0 – 999 文段后,期望能够接受到 1000 之后的 文段,但是主机 B 却给主机 A 发送了一个 1500 之后的 文段,那么主机 A 是否还会继续进行等待呢p>

答案显然是会的,因为 TCP 只会确认流中至第一个丢失字节为止的字节,因为 1500 虽然属于 1000 之后的字节,但是主机 B 没有给主机 A 发送 1000 – 1499 之间的字节,所以主机 A 会继续等待。

在了解完序 和确认 之后,我们下面来聊一下 TCP 的发送过程。下面是一个正常的发送过程

主机 A 给主机 B 的响应可能由于 络抖动等原因无法到达,那么在经过特定的时间间隔后,主机 A 将重新发送 文段。

主机 A 没有收到主机 B 的响应还可能是因为主机 B 在发送给主机 A 的过程中丢失。

TCP RFC 并未为此做任何规定,也就是说,我们可以自己决定如何处理失序到达的 文段。一般处理方式有两种

  • 接收方立刻丢弃失序的 文段

  • 接收方接受时许到达的 文段,并等待后续的 文段

一般来说通常采取的做法是第二种。

传输控制

利用窗口控制提高速度

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

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

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

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

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

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

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

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

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

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

连接管理

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

  • 首先,客户端首先向服务器发送一个特殊的 TCP 文段。这个 文段首部不包含应用层数据,但是在 文段的首部中有一个 被置为 1。因此,这个特殊的 文段也可以叫做 SYN 文段。然后,客户端随机选择一个 ,并将此数字放入初始 TCP SYN 段的序列 字段中,SYN 段又被封装在 IP 数据段中发送给服务器。

  • 一旦包含 IP 数据段到达服务器后,服务端会从 IP 数据段中提取 TCP SYN 段,将 TCP 缓冲区和变量分配给连接,然后给客户端发送一个连接所允许的 文段。这个连接所允许的 文段也不包括任何应用层数据。然而,它却包含了三个非常重要的信息。

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

  • 首先,SYN 比特被置为 1 。

  • 然后,TCP 文段的首部确认 被设置为 。

  • 最后,服务器选择自己的,并将其放置到 TCP 文段首部的序 字段中。

如果用大白话解释下就是,我收到了你发起建立连接的 SYN 文段,这个 文段具有首部字段 client_isn。我同意建立该连接,我自己的初始序 是 server_isn。这个允许连接的 文段被称为

  • 第三步,在收到 SYNACK 文段后,客户端也要为该连接分配缓冲区和变量。客户端主机向服务器发送另外一个 文段,最后一个 文段对服务器发送的响应 文做了确认,确认的标准是客户端发送的数据段中确认 为 server_isn + 1,因为连接已经建立,所以 SYN 比特被置为 0 。以上就是 TCP 建立连接的三次数据段发送过程,也被称为 。

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

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

  • : 表示等待任何来自远程 TCP 和端口的连接请求。

  • : 表示发送连接请求后等待匹配的连接请求。

  • : 表示已接收并发送连接请求后等待连接确认,也就是 TCP 三次握手中第二步后服务端的状态

  • : 表示已经连接已经建立,可以将应用数据发送给其他主机

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

  • : 表示等待来自远程 TCP 的连接终止请求,或者等待先前发送的连接终止请求的确认。

  • : 表示等待来自远程 TCP 的连接终止请求。

  • : 表示等待本地用户的连接终止请求。

  • : 表示等待来自远程 TCP 的连接终止请求确认。

  • : 表示等待先前发送给远程 TCP 的连接终止请求的确认(包括对它的连接终止请求的确认)。

  • : 表示等待足够的时间以确保远程 TCP 收到其连接终止请求的确认。

  • : 表示连接已经关闭,无连接状态。

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

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

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

三次握手建立连接

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

TCP 断开连接需要历经的过程如下

  1. 客户端应用程序发出释放连接的 文段,并停止发送数据,主动关闭 TCP 连接。客户端主机发送释放连接的 文段, 文段中首部 FIN 位置为 1 ,不包含数据,序列 位 seq = u,此时客户端主机进入 阶段。

  2. 服务器主机接受到客户端发出的 文段后,即发出确认应答 文,确认应答 文中 ACK = 1,生成自己的序 位 seq = v,ack = u + 1,然后服务器主机就进入 状态,这个时候客户端主机 -> 服务器主机这条方向的连接就释放了,客户端主机没有数据需要发送,此时服务器主机是一种半连接的状态,但是服务器主机仍然可以发送数据。

  3. 客户端主机收到服务端主机的确认应答后,即进入 的状态。等待客户端发出连接释放的 文段。

  4. 当服务器主机没有数据发送后,应用进程就会通知 TCP 释放连接。这时服务端主机会发出断开连接的 文段, 文段中 ACK = 1,序列 seq = w,因为在这之间可能已经发送了一些数据,所以 seq 不一定等于 v + 1。ack = u + 1,在发送完断开请求的 文后,服务端主机就进入了 的阶段。

  5. 客户端收到服务端的断开连接请求后,客户端需要作出响应,客户端发出断开连接的 文段,在 文段中,ACK = 1, 序列 seq = u + 1,因为客户端从连接开始断开后就没有再发送数据,ack = w + 1,然后进入到 状态,请注意,这个时候 TCP 连接还没有释放。必须经过时间等待的设置,也就是 后,客户端才会进入 状态,时间 MSL 叫做。

  6. 服务端主要收到了客户端的断开连接确认后,就会进入 CLOSED 状态。因为服务端结束 TCP 连接时间要比客户端早,而整个连接断开过程需要发送四个 文段,因此释放连接的过程也被称为四次挥手。

什么是 TIME-WAIT

我上面只是简单提到了一下 TIME-WAIT 状态和 2MSL 是啥,下面来聊一下这两个概念。

是 TCP 文段可以存活或者驻留在 络中的最长时间。RFC 793 定义了 MSL 的时间是两分钟,但是具体的实现还要根据程序员来指定,一些实现采用了 30 秒的这个最大存活时间。

那么为什么要等待 呢p>

主要是因为两个理由

  • 为了保证最后一个响应能够到达服务器,因为在计算机 络中,最后一个 ACK 文段可能会丢失,从而致使客户端一直处于 状态等待客户端响应。这时候服务器会重传一次 FINACK 断开连接 文,客户端接收后再重新确认,重启定时器。如果客户端不是 2MSL ,在客户端发送 ACK 后直接关闭的话,如果 文丢失,那么双方主机会无法进入 CLOSED 状态。

  • 还可以防止的 文段。客户端在发送最后一个 ACK 之后,再经过经过 2MSL,就可以使本链接持续时间内所产生的所有 文段都从 络中消失。从保证在关闭连接后不会有还在 络中滞留的 文段去骚扰服务器。

这里注意一点:在服务器发送了 FIN-ACK 之后,会立即启动超时重传计时器。客户端在发送最后一个 ACK 之后会立即启动时间等待计时器。

说好的 RST 呢

说好的 、、 标志用于连接的建立和关闭,那么 SYN 和 FIN 都现身了,那 RST 呢啊,我们上面探讨的都是一种理想的情况,就是客户端服务器双方都会接受传输 文段的情况,还有一种情况是当主机收到 TCP 文段后,其 IP 和端口 不匹配的情况。假设客户端主机发送一个请求,而服务器主机经过 IP 和端口 的判断后发现不是给这个服务器的,那么服务器就会发出一个 特殊 文段给客户端。

TCP 拥塞控制

如果你看到这里,那我就暂定认为你了解了 TCP 实现可靠性的基础了,那就是使用序 和确认 。除此之外,另外一个实现 TCP 可靠性基础的就是 TCP 的拥塞控制。如果说

TCP 所采用的方法是让每一个发送方根据所感知到的 络的拥塞程度来限制发出 文段的速率,如果 TCP 发送方感知到没有什么拥塞,则 TCP 发送方会增加发送速率;如果发送方感知沿着路径有阻塞,那么发送方就会降低发送速率。

但是这种方法有三个问题

  1. TCP 发送方如何限制它向其他连接发送 文段的速率呢li>

文章知识点与官方知识档案匹配,可进一步学习相关知识 络技能树首页概览22964 人正在系统学习中

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2022年1月16日
下一篇 2022年1月16日

相关推荐