40 张图带你搞懂 TCP 和 UDP,音视频开发工程师面试题

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

TCP


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

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

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

这个连接是指各种设备、线路或者网络中进行通信的两个应用程序为了相互传递消息而专有的、虚拟的通信链路,也叫做虚拟电路。

一旦主机 A 和主机 B 建立了连接,那么进行通信的应用程序只使用这个虚拟的通信线路发送和接收数据就可以保证数据的传输,TCP 协议负责控制连接的建立、断开、保持等工作。

TCP 连接是全双工服务(full-duplex service) 的,全双工是什么意思?全双工指的是主机 A 与另外一个主机 B 存在一条 TCP 连接,那么应用程数据就可以从主机 B 流向主机 A 的同时,也从主机 A 流向主机 B。

TCP 只能进行 点对点(point-to-point) 连接,那么所谓的多播,即一个主机对多个接收方发送消息的情况是不存在的,TCP 连接只能连接两个一对主机。

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

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

主机之间的发送是以 报文段(segment) 进行的,那么什么是 Segement 呢?

TCP 会将要传输的数据流分为多个块(chunk),然后向每个 chunk 中添加 TCP 标头,这样就形成了一个 TCP 段也就是报文段。每一个报文段可以传输的长度是有限的,不能超过最大数据长度(Maximum Segment Size),俗称 MSS。在报文段向下传输的过程中,会经过链路层,链路层有一个 Maximum Transmission Unit ,最大传输单元 MTU, 即数据链路层上所能通过最大数据包的大小,最大传输单元通常与通信接口有关。

那么 MSS 和 MTU 有啥关系呢?

因为计算机网络是分层考虑的,这个很重要,不同层的称呼不一样,对于传输层来说,称为报文段而对网络层来说就叫做 IP 数据包,所以,MTU 可以认为是网络层能够传输的最大 IP 数据包,而 MSS(Maximum segment size)可以认为是传输层的概念,也就是 TCP 数据包每次能够传输的最大量

TCP 报文段结构

在简单聊了聊 TCP 连接后,下面我们就来聊一下 TCP 的报文段结构,如下图所示

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

  • 32 比特的序号字段(sequence number field) 和 32 比特的确认号字段(acknowledgment number field) 。这些字段被 TCP 发送方和接收方用来实现可靠的数据传输。

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

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

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

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

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

序号、确认号实现传输可靠性

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

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

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

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

至于确认号的话,会比序号要稍微麻烦一些。这里我们先拓展下几种通信模型。

  • 单工通信:单工数据传输只支持数据在一个方向上传输;在同一时间只有一方能接受或发送信息,不能实现双向通信,比如广播、电视等。

  • 双工通信是一种点对点系统,由两个或者多个在两个方向上相互通信的连接方或者设备组成。双工通信模型有两种:全双工(FDX)和半双工(HDX)

  • 全双工:在全双工系统中,连接双方可以相互通信,一个最常见的例子就是电话通信。全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。

  • 半双工:在半双工系统中,连接双方可以彼此通信,但不能同时通信,比如对讲机,只有把按钮按住的人才能够讲话,只有一个人讲完话后另外一个人才能讲话。

单工、半双工、全双工通信如下图所示

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

累积确认

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

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

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

TCP 通过肯定的确认应答(ACK) 来实现可靠的数据传输,当主机 A将数据发出之后会等待主机 B 的响应。如果有确认应答(ACK),说明数据已经成功到达对端。反之,则数据很可能会丢失。

如下图所示,如果在一定时间内主机 A 没有等到确认应答,则认为主机 B 发送的报文段已经丢失,并进行重发。

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

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

如上图所示,由主机 B 返回的确认应答,由于网络拥堵等原因在传送的过程中丢失,并没有到达主机 A。主机 A 会等待一段时间,如果在这段时间内主机 A 仍没有等到主机 B 的响应,那么主机 A 会重新发送报文段。

那么现在就存在一个问题,如果主机 A 给主机 B 发送了一个报文段后,主机 B 接受到报文段发送响应,此刻由于网络原因,这个报文段并未到达,等到一段时间后主机 A 重新发送报文段,然后此时主机 B 发送的响应在主机 A 第二次发送后失序到达主机 A,那么主机 A 应该如何处理呢?

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

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

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

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

传输控制

利用窗口控制提高速度

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

那么如何提升性能呢?

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

如下图所示

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

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

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

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

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

窗口控制和重发

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

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

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

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

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

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

流量控制

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

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

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

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

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

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

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

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

如上图所示,当主机 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 ,整个过程描述如下图所示

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

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

在一个 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(关闭)状态。

  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 建立一个连接需要三个报文段,释放一个连接却需要四个报文段。

四次挥手

数据传输结束后,通信的双方可以释放连接。数据传输结束后的客户端主机和服务端主机都处于 ESTABLISHED 状态,然后进入释放连接的过程。

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

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

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

  3. 客户端主机收到服务端主机的确认应答后,即进入 FIN-WAIT-2(终止等待2) 的状态。等待客户端发出连接释放的报文段。

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

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

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

什么是 TIME-WAIT

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

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

那么为什么要等待 2MSL 呢?

主要是因为两个理由

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

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

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

说好的 RST 呢

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

因此,当服务端发送一个 RST 特殊报文段给客户端的时候,它就会告诉客户端_没有匹配的套接字连接,请不要再继续发送了_。

上面探讨的是 TCP 的情况,那么 UDP 呢?

使用 UDP 作为传输协议后,如果套接字不匹配的话,UDP 主机就会发送一个特殊的 ICMP 数据报。

SYN 洪泛攻击

下面我们来讨论一下什么是 SYN 洪泛攻击

我们在 TCP 的三次握手中已经看到,服务器为了响应一个收到的 SYN,分配并初始化变量连接和缓存,然后服务器发送一个 SYNACK 作为响应,然后等待来自于客户端的 ACK 报文。如果客户端不发送 ACK 来完成最后一步的话,那么这个连接就处在一个挂起的状态,也就是半连接状态。

攻击者通常在这种情况下发送大量的 TCP SYN 报文段,服务端继续响应,但是每个连接都完不成三次握手的步骤。随着 SYN 的不断增加,服务器会不断的为这些半开连接分配资源,导致服务器的连接最终被消耗殆尽。这种攻击也是属于 Dos 攻击的一种。

抵御这种攻击的方式是使用 SYN cookie ,下面是它的工作流程介绍

  • 当服务器收到一个 SYN 报文段时,它并不知道这个报文段是来自哪里,是来自攻击者主机还是客户端主机(虽然攻击者也是客户端,不过这么说更便于区分) 。因此服务器不会为报文段生成一个半开连接。与此相反,服务器生成一个初始的 TCP 序列号,这个序列号是 SYN 报文段的源和目的 IP 地址与端口号这个四元组构造的一个复杂的散列函数,这个散列函数生成的 TCP 序列号就是 SYN Cookie,用于缓存 SYN 请求。然后,服务器会发送带着 SYN Cookie 的 SYNACK 分组。有一点需要注意的是,服务器不会记忆这个 Cookie 或 SYN 的其他状态信息

  • 如果客户端不是攻击者的话,它就会返回一个 ACK 报文段。当服务器收到这个 ACK 后,需要验证这个 ACK 与 SYN 发送的是否相同,验证的标准就是确认字段中的确认号和序列号,源和目的 IP 地址与端口号以及和散列函数的是否一致,散列函数的结果 + 1 是否和 SYNACK 中的确认值相同。(大致是这样,说的不对还请读者纠正) 。如果有兴趣读者可以自行深入了解。如果是合法的,服务器就会生成一个具有套接字的全开连接。

  • 如果客户端没有返回 ACK,即认为是攻击者,那么这样也没关系,服务器没有收到 ACK,不会分配变量和缓存资源,不会对服务器产生危害。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

总结

【Android 详细知识点思维脑图(技能树)】

我个人是做Android开发,已经有十来年了,目前在某创业公司任职CTO兼系统架构师。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

详细整理在GitHub可以见;

Android架构视频+BAT面试专题PDF+学习笔记

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

**
[外链图片转存中…(img-01arxPeN-1711129574240)]

总结

【Android 详细知识点思维脑图(技能树)】

[外链图片转存中…(img-WpTumtkY-1711129574240)]

我个人是做Android开发,已经有十来年了,目前在某创业公司任职CTO兼系统架构师。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

[外链图片转存中…(img-Br0sylUL-1711129574241)]

详细整理在GitHub可以见;

Android架构视频+BAT面试专题PDF+学习笔记

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

最后,赠与大家一句话,共勉!

  • 21
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值