【网络】传输层协议TCP(重点)

文章目录

  • [1. TCP协议段格式](#1. TCP协议段格式)
  • [2. 详解TCP](#2. 详解TCP)
    • [2.1 4位首部长度](#2.1 4位首部长度)
    • [2.2 32位序号与32位确认序号(确认应答机制)](#2.2 32位序号与32位确认序号(确认应答机制))
    • [2.3 超时重传机制](#2.3 超时重传机制)
    • [2.4 连接管理机制(3次握手、4次挥手 + 3个标志位)](#2.4 连接管理机制(3次握手、4次挥手 + 3个标志位))
    • [2.5 16位窗口大小(流量控制)](#2.5 16位窗口大小(流量控制))
    • [2.6 滑动窗口](#2.6 滑动窗口)
    • [2.7 3个标志位 + 16位紧急指针](#2.7 3个标志位 + 16位紧急指针)
    • [2.8 拥塞控制](#2.8 拥塞控制)
    • [2.9 延迟应答](#2.9 延迟应答)
    • [2.10 其它](#2.10 其它)
      • [2.10.1 面向字节流](#2.10.1 面向字节流)
      • [2.10.2 粘包问题](#2.10.2 粘包问题)
      • [2.10.3 异常情况](#2.10.3 异常情况)
  • [3. TCP/UDP 对比](#3. TCP/UDP 对比)


TCP协议全称为 "传输控制协议(Transmission Control Protocol")。
人如其名,要对数据的传输进行一个 详细的控制

可靠性:

  • 校验和
  • 序列号(按序到达) (去重)
  • 确认应答
  • 超时重传
  • 连接管理
  • 流量控制
  • 拥塞控制

提高性能:

  • 滑动窗口
  • 快重传
  • 延迟应答
  • 捎带应答

其他:

  • 定时器(超时重传定时器, 保活定时器, TIME_WAIT 定时器等)

1. TCP协议段格式

  • 16位源/目的端口号:表示数据是从哪个进程来, 到哪个进程去;
  • 32位序号/32 位确认序号
  • 4 位首部长度: 表示该 TCP 头部有多少个 32 位 bit(有多少个4 字节); 所以 TCP 头部最大长度是 15 * 4 = 60
  • 6 位标志位
    • ACK:确认号是否有效
    • SYN:请求建立连接;我们把携带 SYN 标识的称为同步报文段
    • FIN:通知对方, 本端要关闭了, 我们称携带 FIN 标识的为结束报文段
    • PSH: 提示接收端应用程序立刻从 TCP 缓冲区把数据读走
    • RST:对方要求重新建立连接; 我们把携带 RST标识的称为复位报文段
    • URG:紧急指针是否有效
  • 16 位窗口大小
  • 16 位校验和:发送端填充,CRC 校验。接收端校验不通过,则认为数据有问题,此处的检验和不光包含 TCP 首部,也包含TCP 数据部分.
  • 16 位紧急指针:标识哪部分数据是紧急数据;
  • 40 字节头部选项:暂时忽略

下面的是Linux源代码中,tcp报头的定义:

c 复制代码
struct tcphdr {
    __be16 source;          // 源端口号
    __be16 dest;            // 目的端口号
    __be32 seq;             // 序列号
    __be32 ack_seq;         // 确认号
#if defined(__LITTLE_ENDIAN_BITFIELD)
	//使用了位段
    __u16 res1:4,           // 保留位
          doff:4,           // 数据偏移(头部长度,以32位字为单位)
          fin:1,            // FIN标志:结束连接
          syn:1,            // SYN标志:同步序列号
          rst:1,            // RST标志:重置连接
          psh:1,            // PSH标志:Push函数
          ack:1,            // ACK标志:确认字段有效
          urg:1,            // URG标志:紧急指针字段有效
          ece:1,            // ECN回显标志
          cwr:1;            // 拥塞窗口减少标志
#elif defined(__BIG_ENDIAN_BITFIELD)
    __u16 doff:4,           // 数据偏移(头部长度,以32位字为单位)
          res1:4,           // 保留位
          cwr:1,            // 拥塞窗口减少标志
          ece:1,            // ECN回显标志
          urg:1,            // URG标志:紧急指针字段有效
          ack:1,            // ACK标志:确认字段有效
          psh:1,            // PSH标志:Push函数
          rst:1,            // RST标志:重置连接
          syn:1,            // SYN标志:同步序列号
          fin:1;            // FIN标志:结束连接
#else
#error "Adjust your <asm/byteorder.h> defines"
#endif
    __be16 window;          // 窗口大小
    __sum16 check;          // 校验和
    __be16 urg_ptr;         // 紧急指针
};

2. 详解TCP

2.1 4位首部长度

4位首部长度 = 标准报头长度 + 选项长度,单位是4字节。

4个比特位可表示的范围是 [0,15],可表示的大小就是 [0,60]字节,由于标准报头占 20 字节,所以4位首部长度的范围是 [20,60]。

所以,TCP解包时,先读取报文的前20字节,然后再根据4位首部长度,将报头+选项提取出来,剩下的就是有效载荷的长度。

2.2 32位序号与32位确认序号(确认应答机制)

首先我们要知道,32位序号是用来保证收到的报文的可靠性 的(对历史报文的可靠性)。

TCP中的可靠性主要是依靠确认应答实现的,否则发送方不知道自己发送的报文是否被收到了。

只要发送端收到了应答,说明发送的数据一定被收到了,可靠性也就保证了。(接收端无需关心自己的应答是否可靠,如果不可靠,发送端会重发数据;如果可靠,发送端就发新的数据了)

那什么是确认呢?

确认,至少是一个"裸"的tcp报头

32位序号又是什么呢?

根据我们上面所说的,一条请求对应一条应答,没有收到应答就会重新发送请求;如果是串行的话,效率就太低了,所以TCP选择的是并行发送。

并行发送会存在一个问题,不知道应答对应哪一条请求,所以必须对请求编号,这个编号就是32位序号

32位确认序号就是对报文的序号+1,表示序号之前的内容已经收到了
序号与确认序号不一定是一对一的,多个序号可能只会有一条确认序号,表示该序号之前的内容已全部收到)

序号存在的另一个原因:保证报文的按序到达

报文如果到达后是乱序的,这也是不可靠的的表现,所以可以根据序号排序,然后按顺序入缓冲区。

可是报头中为什么要有两个32位序号呢?一个也够用呀?

两个32位序号,是为了实现捎带应答机制。接收端应答的同时,也想捎带着给发送端发送数据。

所以,TCP报文在很大概率上,既是应答,也是数据。

那序号又是如何产生的呢?

2.3 超时重传机制

主机 A 发送数据给 B 之后,可能因为网络拥堵等原因,数据无法到达主机 B;如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答,就会进行重发;

但是,主机 A 未收到 B 发来的确认应答, 也可能是因为应答丢失

因此主机 B 会收到很多重复数据。那么 TCP 协议需要能够识别出那些包是重复的包, 并且把重复的丢弃掉。

这时候我们可以利用前面提到的序列号, 就可以很容易做到去重的效果。

所以,为了降低重复率,不能让发送方一直发,需要设定一个时间,超过这个时间后,发送端再发,这种机制叫做超时重传机制。

那超时的时间如何确定呢?

  • 最理想的情况下, 找到一个最小的时间, 保证 "确认应答一定能在这个时间内返回"。
  • 但是这个时间的长短,随着网络环境的不同,是有差异的。 如果超时时间设的太长,会影响整体的重传效;如果超时时间设的太短,有可能会频繁发送重复的包。

TCP 为了保证无论在任何环境下都能比较高性能的通信,因此会动态计算这个最大超时时间

Linux 中(BSD Unix 和 Windows 也是如此),超时以 500ms 为一个单位进行控制,每次判定超时重发的超时时间都是 500ms 的整数倍。

  • 如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传。
  • 如果仍然得不到应答,等待 4*500ms 进行重传, 依次类推, 以指数形式递增。
  • 累计到一定的重传次数, TCP 认为网络或者对端主机出现异常,强制关闭连接。

2.4 连接管理机制(3次握手、4次挥手 + 3个标志位)

在正常情况下,TCP 要经过三次握手建立连接,四次挥手断开连接。

在正式学习握手、挥手之前,先了解报头中的几个标志位。

在TCP报头中,有6个标志位,用来区分接收端收到的TCP报文的类型 (可能有多个发送端)。

  1. ACK:acknowledgement

表明自己是一个确认报文,让对方关心确认序号。 (因为有捎带应答机制,所以大部分的TCP报文的ACK标志位都为1)

  1. SYN:synchronize

同步标志位,即表明是一个建立连接的请求

  1. FIN:finish

表明自己是一个断开连接的请求,一般用于通信结束时。


双方建立连接,首先要进行3次握手

举个栗子:

男:你愿意做我女朋友吗?

女:好呀,什么时候开始?

男:就现在!

在上面的例子中,双方用了最小的握手次数,建立了关系,这就叫做三次握手

双方断开连接,首先要进行4次挥手

举个栗子:

女:我们分手吧!

男:好!

男:我也要跟你分手!

女:好!

为什么叫做四次挥手? - 因为断开连接需要征得双方的同意 ! (因为TCP是全双工的,要关闭两个朝向上的连接)


3次握手,是由操作系统自动完成的。

服务器端:accept返回后,连接已经建立完成了。即accept等3次握手完成,它不参与3次握手

客户端:connect调用后,触发操作系统,让操作系统发送SYN,双方握手完成,connect返回。

  • 只要客户端发出去SYN,它的状态就变成了SYN_SENT;客户端发出去ACK,就认为自己把连接建立好了,状态变为established。(客户端不保证发送的ACK一定能被收到,所以3次握手本质就是在赌,因为3次握手本来就不一定成功)
    • 服务端未收到ACK,但发送端以为连接建立成功了,发送端此时就会发送数据,但是服务端不认识它,会通过标志位RST要求重新建立连接。
  • 一般服务端只要收到了SYN,它的状态就变成SYN_RECV;它收到客户端的ACK后,才认为连接建立完成。
  • 所以,一般是客户端认为连接先建立好。

有了四次挥手的理解,3次握手的本质,其实也是四次握手!

所以,为什么要3次握手呢?

  1. 建立连接,要征得双方的同意;因为TCP是全双工的,要建立两个朝向上的连接
  2. 在3次握手期间,正式通信之前,双方验证了全双工信道的通畅性(客户端与服务端的IO是正常的,即网络是通畅的)

谈了这么多,到底什么是连接呢?

  • 一条连接,一定会和一个文件对应;因为一个连接,对应一个文件描述符。
  • 那么,连接在操作系统内就会存在很多个,操作系统一定要管理连接。先描述在组织,创建连接的struct,在struct内部,一定会有一个字段来表示连接的状态。

下面我们再来看一下4次挥手

介绍一个系统调用,shutdown可控制关闭连接的读写端

我们具体是使用close还是shutdown,取决于应用层。

在服务器这边,如果不调用close关闭sockfd,那就只会进行两次挥手,server会一直处于close_wait状态,会造成文件描述符泄漏、内存泄漏问题。

当服务器关闭后,server会进入last_ack状态,可是此时客户端早就关闭了,没人给它应答了,那么服务端在一段时间后,自动进入closed状态。

那客户端的time_wait状态是什么意思呢??

  • 在四次挥手时,主动断开连接的一方会进入time_wait状态,要等待一个 2MSL(Max Segment Life,报文最大生存时间),才会进入 CLOSED 状态

为什么会这样呢?举个例子:

  • 在有些情况下,双方都关闭后,接收端重启并与发送端建立连接后,发送方被判定为超时的报文可能又到达了。为了防止报文被接收端误处理,发送方需要等待2MSL后才可再次启动。

等待2MSL的目的是:

  • 等待历史的游离报文,在网络中消散!
  • 若time_wait状态下的ACK丢了,那么就可以以最快的速度重新发送,尽可能正常的完成4次挥手断开连接

为什么是2MSL呢?MSL不行吗?

  • 理想情况下,1个MSL时间足以确保一个报文在网络中消散
    • 报文在网络中传输时,会经历各种延迟,包括路由器处理延迟、链路传输延迟等。这些延迟是不确定的,可能会导致报文在较长时间内仍然存在于网络中。
  • 等待2MSL时间可以确保旧连接的所有报文(包括丢失的报文和重传的报文)在网络中完全消失。
    • 假设MSL为30秒:
    • 丢失的报文:一个报文在接近30秒时丢失。
    • 重传的报文:发送方在超时后(假设超时时间为1秒)重传该报文,重传的报文也会在网络中传输,其生存时间也是30秒。
      总时间:因此,最坏情况下,报文的总生存时间是30秒(丢失的报文)+ 30秒(重传的报文)= 60秒。
  • 如果ACK报文丢失,被动关闭方重传的FIN报文也需要在网络中传输,这同样需要一个MSL时间。因此,总共需要2MSL时间来确保ACK报文的可靠传输和FIN报文的重传处理。

在我们前面写代码时,端口号绑定失败的原因:

  • 当服务端主动关闭后,其进入time_wait状态,即进程没有退出,端口号被占用了。
  • 若想使用旧端口号,可以通过系统调用 setsockopt()设置套接字的类型

可以通过 cat /proc/sys/net/ipv4/tcp_fin_timeout 查看 msl 的值

2.5 16位窗口大小(流量控制)

接收端处理数据的速度是有限的。如果发送端发的太快,导致接收端的缓冲区被打满,这个时候如果发送端继续发送,就会造成丢包,继而引起丢包重传等等一系列连锁反应,不做任何处理则会浪费了各种资源(网络带宽、CPU等等)。

因此 TCP 支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制

接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 "窗口大小" 字段

  • 窗口大小字段越大, 说明网络的吞吐量越高,发送端接受到这个窗口之后, 就会提高自己的发送速度
  • 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端;发送端接受到这个窗口之后, 就会减慢自己的发送速度
  • 如果接收端缓冲区满了,就会将窗口置为 0;这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端。
  • 双方都要进行流量控制
  • 首次发送如何知道对方的接收能力呢? 三次握手时,是做过报文交换与窗口协商的!

接收端如何把窗口大小告诉发送端呢? TCP 首部中,有一个 16 位窗口大小字段,就是存放了窗口大小信息(即自己接收缓冲区中剩余空间的大小);

那么问题来了,16 位数字最大表示 65535, 那么 TCP 窗口最大就是 65535 字节么?

实际上,TCP 首部 40 字节选项中 还包含了一个窗口扩大因子 M,实际窗口大小是窗口字段的值左移 M 位;

2.6 滑动窗口

在我们讨论了确认应答策略时, 对每一个发送的数据段,都要给一个 ACK 确认应答,收到 ACK 后再发送下一个数据段(串行发送 )。

这样做有一个比较大的缺点:就是性能较差,尤其是数据往返的时间较长的时候。

我们说TCP是采用并行发送的,它是怎么实现的呢?流量控制又是怎么实现的呢? - - 滑动窗口

窗口大小指的是:无需等待确认应答就可以继续发送数据的最大值。 下图的窗口大小就是 4000 个字节(四个段)

  • 发送前四个段的时候, 不需要等待任何 ACK, 直接发送;
  • 收到第一个 ACK 后, 滑动窗口向后移动(start = ACK),继续发送第五个段的数据(end = start + 16位窗口大小),依次类推;
  • 操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答;只有确认应答过的数据,才能从缓冲区删掉
  • 窗口越大,则网络的吞吐率就越高;窗口越小,网络的吞吐率越低。(流量控制)

此时就是并行发送的了

那么如果出现了丢包,如何进行重传?这里分两种情况讨论:

  1. 情况一: 数据包已经抵达, ACK 被丢了

这种情况下, 部分 ACK 丢了并不要紧,因为可以通过后续的 ACK 进行确认;

  1. 情况二:数据包就直接丢了

当某一段报文段丢失之后,发送端会一直收到 1001 这样的 ACK,就像是在提醒发送端 "我想要的是 1001" 一样,滑动窗口会先向右移动到已经发送成功处,然后补发丢失的报文。

  • 如果发送端主机连续三次收到了同样一个 "1001" 这样的应答, 就会将对应的数 据 1001 - 2000 重新发送;
  • 这个时候接收端收到了 1001 之后, 再次返回的 ACK 就是 7001 了(因为 2001 - 7000)接收端其实之前就已经收到了, 被放到了接收端操作系统内核的接收缓冲区中 ,这种机制被称为 "高速重发控制"(也叫 "快重传).

既然有了快重传,它既快,又能重传,那为什么还要超时重传呢?

快重传是有条件的:要连续三次收到同一个应答!
万一发送方只发送了2个报文呢?最多就只能收到2个应答呗 ,那就无法触发快重传,只能超时重传。所以,超时重传是兜底的;快重传是提高效率的

2.7 3个标志位 + 16位紧急指针

有了上面的理解,我们来了解一下TCP报头中剩余的3个标志位

  1. PSH:push

在进行流量控制时,如果接收方的缓冲区已满,那发送方也就只能发送探测报文,没有别的办法了。

为了告诉对方,请尽快将缓冲区中的数据交给上层,就引入了PSH标志位;也可利用PSH标志位,告诉对端,我的数据比较重要,请尽快交付。

  1. RST:reset

重置连接(重新三次握手)

在三次握手时,服务端未收到ACK,但发送端以为连接建立成功了,发送端此时就会发送数据,但是服务端不认识它,会通过标志位RST要求重新建立连接。

  1. URG:urgent

表示紧急报文,优先让上层从缓冲区中读取。

那紧急数据在哪里呢?

在TCP报头中,有16位紧急指针,表示紧急数据在有效载荷中的偏移量,通过它就可以获取紧急数据。

但是只有紧急数据的起始地址,紧急数据有多长呢?

TCP允许插队,但不允许过度插队, 紧急数据只占一个字节! 以后可以在紧急数据中设置状态码(如终止连接、暂停上传等等)

在系统调用recv中,可以设置标志位MSG_OOB,来读取紧急数据。

2.8 拥塞控制

虽然 TCP 有了滑动窗口这个大杀器,能够高效可靠的发送大量的数据,但是如果在刚开始阶段就发送大量的数据,仍然可能引发问题。

因为网络上有很多的计算机,可能当前的网络状态就已经比较拥堵。在不清楚当前网络状态下,贸然发送大量的数据,是很有可能引起雪上加霜的。 所以TCP使用拥塞控制来考虑网络的健康状况, 一旦发送的报文大量丢失,则会被判定为网络拥塞。

大量报文丢失后,能不能直接重传呢?- - - 不能,因为可能会造成网络更加的拥堵!应该等一等

TCP 引入慢启动机制,先发少量的数据,探探路,摸清当前的网络拥堵状态,再决定按照多大的速度传输数据。

此处引入一个拥塞窗口的概念,拥塞窗口是衡量网络拥堵的指标。

  • 发送开始的时候,定义拥塞窗口大小为 1
  • 每次收到一个 ACK 应答,拥塞窗口加 1 倍

滑动窗口 = min (拥塞窗口,对端接收缓冲区剩余空间的大小)

像上面这样的拥塞窗口增长速度,是指数级别的。"慢启动" 只是指初使时慢,但是增长速度非常快 (指数级增长)。

可是为什么使用指数级增长呢?

指数增长的特点是:前期慢,后期快;既然前面慢速度发送的都没有问题,那就应该尽快进行网络的恢复。

但是,为了不增长的那么快,不能使拥塞窗口单纯的加倍;此处引入一个叫做慢启动的阈值,当拥塞窗口超过这个阈值 的时候,不再按照指数方式增长,而是按照线性方式增长


拥塞控制算法 = 慢启动 + 加法增大 + 乘法减小

可是这个拥塞窗口为什么一直在试探性的增大呢?

拥塞窗口是网络健康状况的评估值,网络的状况是一直在变化的,所以要反复的试探,尽量让下一次的阈值高一点。

拥塞控制,归根结底是 TCP 协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案。

2.9 延迟应答

接收端收到数据后,如果接收数据的主机立刻返回 ACK 应答,这时候返回的窗口可能比较小(上层未取走刚接收到的报文)

  • 假设接收端缓冲区为 1M,一次收到了 500K 的数据,如果立刻应答,返回的窗口就是 500K;
  • 但实际上可能处理端处理的速度很快, 10ms 之内就把 500K 数据从缓冲区消费掉了;在这种情况下,接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;
  • 如果接收端稍微等一会再应答,比如等待 200ms 再应答, 那么这个时候返回的窗口大小就是 1M;
  • 一定要记得, 窗口越大, 网络吞吐量就越大, 传输效率就越高。我们的目标是在保证网络不拥塞的情况下尽量提高传输效率;

那么所有的包都可以延迟应答么? 肯定也不是

  • 数量限制: 每隔 N 个包就应答一次;
  • 时间限制: 超过最大延迟时间就应答一次;
  • 具体的数量和超时时间,依操作系统不同也有差异;一般 N 取 2,超时时间取 200ms;

2.10 其它

2.10.1 面向字节流

创建一个 TCP 的 socket,同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区

  • 调用 write 时, 数据会先写入发送缓冲区中; 如果发送的字节数太长,会被拆分成多个 TCP 的数据包发出;
  • 如果发送的字节数太短,就会先在缓冲区里等待,等到缓冲区长度差不多了,或者其他合适的时机发送出去;
  • 接收数据的时候,数据也是从网卡驱动程序到达内核的接收缓冲区;然后应用程序可以调用 read 从接收缓冲区拿数据;
  • 另一方面,TCP 的一个连接,既有发送缓冲区,也有接收缓冲区,那么对于这一个连接,既可以读数据,也可以写数据,这个概念叫做全双工

由于缓冲区的存在, TCP 程序的读和写不需要一一匹配,例如:

  • 写 100 个字节数据时,可以调用一次 write 写 100 个字节, 也可以调用 100 次write,每次写一个字节;
  • 读 100 个字节数据时,也完全不需要考虑写的时候是怎么写的,既可以一次read 100 个字节, 也可以一次 read 一个字节,重复 100 次
  • 具体传输的数据是什么,由上层解释。

2.10.2 粘包问题

首先要明确,粘包问题中的 "包" ,是指的应用层的数据包。

  • 在 TCP 的协议头中,没有如同 UDP 一样的 "报文长度" 这样的字段, 但是有一个序号这样的字段
  • 站在传输层的角度,TCP 是一个一个报文过来的,按照序号排好序放在缓冲区中
  • 站在应用层的角度,看到的只是一串连续的字节数据
  • 那么应用程序看到了这么一连串的字节数据,就不知道从哪个部分开始,到哪个部分是一个完整的应用层数据包

那么如何避免粘包问题呢? 归根结底就是一句话,明确两个包之间的边界

  • 对于定长的包,保证每次都按固定大小读取即可;那么就从缓冲区从头开始按固定大小依次读取即可;
  • 对于变长的包,可以在包头的位置,约定一个包总长度的字段,从而就知道了包的结束位置;
  • 对于变长的包,还可以在包和包之间使用明确的分隔符(应用层协议,是程序猿自己来定的,只要保证分隔符不和正文冲突即可)

思考: 对于 UDP 协议来说,是否也存在 "粘包问题" 呢?

  • 对于 UDP,如果还没有给上层交付数据,UDP 的报文长度仍然在;同时,UDP 是一个一个把数据交付给应用层,就有很明确的数据边界.
  • 站在应用层的站在应用层的角度,使用 UDP 的时候, 要么收到完整的 UDP 报文,要么不收,不会出现"半个"的情况

2.10.3 异常情况

  • 进程终止:进程终止会释放文件描述符,仍然可以发送 FIN,和正常关闭没有什么区别
  • 机器重启:和进程终止的情况相同.
  • 机器掉电/网线断开:接收端认为连接还在,一旦接收端有写入操作,接收端发现连接已经不在了,就会进行 reset。即使没有写入操作, TCP 自己也内置了一个保活定时器,会定期询问对方是否还在,如果对方不在,也会把连接释放 - - - 连接保活机制。
  • 应用层的某些协议,也有一些这样的检测机制。例如 HTTP 长连接中,也会定期检测对方的状态。例如 QQ在 QQ 断线之后,也会定期尝试重新连接

3. TCP/UDP 对比

  1. TCP/UDP 对比

我们说了 TCP 是可靠连接,那么是不是 TCP 一定就优于 UDP 呢? TCP 和 UDP 之间的优点和缺点。不能简单、绝对的进行比较

  • TCP 用于可靠传输的情况,应用于文件传输,重要状态更新等场景
  • UDP 用于对高速传输和实时性要求较高的通信领域,例如,早期的 QQ、视频传输等;另外 UDP 可以用于广播;

归根结底,TCP 和 UDP 都是程序员的工具,什么时机用,具体怎么用,还是要根据具体的需求场景去判定

  1. 基于 TCP 应用层协议
  • HTTP
  • HTTPS
  • SSH
  • Telnet
  • FTP
  • SMTP
  1. 用 UDP 实现可靠传输(经典面试题)

先根据应用场景,确定具体的应用需求,可靠性要保障到什么程度;再参考 TCP 的可靠性机制, 在应用层实现类似的逻辑;

  • 例如:
  • 引入序列号, 保证数据顺序;
  • 引入确认应答, 确保对端收到了数据;
  • 引入超时重传, 如果隔一段时间没有应答, 就重发数据;
  • ...
相关推荐
sunfove7 小时前
光网络的立交桥:光开关 (Optical Switch) 原理与主流技术解析
网络
Kevin Wang72710 小时前
欧拉系统服务部署注意事项
网络·windows
min18112345610 小时前
深度伪造内容的检测与溯源技术
大数据·网络·人工智能
汤愈韬10 小时前
NAT策略
网络协议·网络安全·security·huawei
汤愈韬11 小时前
Full Cone Nat
网络·网络协议·网络安全·security·huawei
zbtlink11 小时前
现在还需要带电池的路由器吗?是用来干嘛的?
网络·智能路由器
桌面运维家11 小时前
vDisk配置漂移怎么办?VOI/IDV架构故障快速修复
网络·架构
dalerkd11 小时前
忙里偷闲叙-谈谈最近两年
网络·安全·web安全
汤愈韬12 小时前
NAT ALG (应用层网关)
网络·网络协议·网络安全·security·huawei
运维栈记13 小时前
虚拟化网络的根基-网络命名空间
网络·docker·容器