IP 层负责主机和主机之间的通信,但仅仅如此还不足以被实际使用,原因是主机上还有很多不同的进程,进程希望能向目标主机上具体的进程传输数据,而不是笼统地直接以主机为目标发送数据。运输层就是提供了端到端的传输服务,通信的两端就是两个主机的进程。此外,传输层还提供了差异化的传输服务(如 TCP 和 UDP。TCP 提供了数据传播的可靠性,而 UDP 延续了 ip 的 best-effort 特性,只注重快捷)

端口

端口是传输层定义的规范,由一个 16 位整数进行编号,某一类传输层协议(TCP、UDP)最多可以有 65535 个端口。
如果主机是一栋公寓,公寓里每一个进程就是一个房间,IP 地址是楼号,端口就是门牌号。

公认端口 Well-Known Ports

类似于 0.0.0.0 这类特殊的 ip 地址,公认端口是被世界共同接受、用于常用、重要的服务。如:
80 —— HTTP 端口
25 —— FTP 端口
443 —— HTTPS 端口

注册端口 Registered Ports

大型公司的软件使用的已经注册的端口,如 MySQL 的 3306。

动态端口 Dynamic Ports

除上面两种端口以外的接口,可以被应用或者用户自由使用。

套接字

套接字是传输层为应用层开放的接口,它是程序实际使用网络时中最常用的接口。
套接字接口的实现通常由操作系统内核提供。不同的操作系统内核使用的套接字接口定义以及对它的实现不同,例如,许多类 Unix 操作系统(如 Linux、macOS 和 BSD 系统)遵循 POSIX 标准。这意味着在这些系统中,套接字接口定义和实现是相似的。Windows 系统提供的套接字接口称为 Winsock。尽管它也实现了套接字的基本功能,但与 POSIX 套接字的接口存在一些差异。

流式套接字 SOCK_STREAM

基于 TCP(以及 TCP 派生的传输层协议)工作的套接字实现,提供可靠的数据传输,传输数据时需要进行连接。

数据报套接字 SOCK_DGRAM

基于 UDP(以及 UDP 派生的传输层协议)工作的套接字实现,传输数据时无需进行连接。

原始套接字 SOCK_RAW

工作在 IP 层的服务,用于一些特殊的应用,如网络安全应用需要对所有抵达主机的 ip 数据报进行筛选。这种套接字允许直接对 IP 层的网络包进行处理。

UDP 协议

UDP 协议对应用层交付的数据直接加上 UDP 头部后就交付给 IP。UDP 不会主动对数据进行分段。

UDP 报文头部

  • 8 字节的 UDP 首部
    • 2 字节源端口
    • 2 字节目的端口
    • 2 字节报文长度,单位为字节,最大为 65535 字节。
    • 2 字节 UDP 校验

首部固定长度为 8 字节。其中,UDP 校验码是基于伪首部数据部计算得到的互联网校验和。伪首部的定义如下:

  • 12 字节的伪首部
    • 源 IP 地址 4 字节
    • 目的 IP 地址 4 字节
    • 保留字段 1 字节,值为 0x0
    • 协议类型 1 字节,对于 UDP,值为 0x11
    • 长度,与首部的报文长度相同。

伪首部并不实际出现在报文首部,仅用于计算校验和。

可靠传输协议

停止等待 ARQ 协议

自动重传请求 (ARQ, Automatic Repeat reQuest) 协议是一种错误控制协议。它的基本思想是在数据传输过程中,接收方需要向发送方回复确认信息,发送方根据是否接收到确认信息判断数据是否发送失败。

ARQ 能够处理数据丢失和错误。如果发送方发送数据后一定时间内没有收到 ACK,则判定数据丢失,触发重传。如果连续收到 ACK ,则认为数据发送错误,触发重传。另一方面,如果接收方通过检错机制发现数据出错,则不发送 ACK 等待发送方重传(或者连续发送 ACK 触发快速重传)。

ACK 本身也可能在传输中丢失,导致数据传输重复。因此,ARQ 协议规定,需要为报文段进行编号,如果发现编号重复,则删除之。

停止-等待是一种流量控制技术:每次数据段发送后,需要等待接收方发送确认帧(ACK),然后才继续发送下一个数据段,以此来确保数据不会发送过快。

停止等待 ARQ 的信道利用率

在使用停止-等待 ARQ 协议的情况下,信道利用率的定义是数据发送时间(发送时延)在一次完整发送周期(从开始发送到完成接收 ACK 帧的周期)中占用的比例。设 t_s 是数据发送时间(数据长度 / 带宽),RTT 是数据往返时长,信道利用率 p 的定义式如下:

p = \frac{t_s}{t_s + RTT}

分子和分母同时乘以带宽,得到:

p = \frac{数据长度}{数据长度 + RTT\cdot 带宽}

连续 ARQ 协议 (GBN 协议)

现代互联网信道可靠性已经很高,而且带宽也越来越大。根据上文的信道利用率定义式,带宽越大,信道利用率越低,传统 ARQ 协议的效率太低了。信道可靠性较高的情况下,可以适当牺牲重传的代价换取常态的信道利用率提高。
Go-Back-N (GBN) ARQ 是一种连续 ARQ 协议,它允许发送方在得到确认之前连续发送多个数据包。具体实现细节如下:

  • 发送方维护一个大小为 N 的窗口,称为发送窗口。窗口大小 N 决定了发送方可以连续发送多少个数据段,而无需等待确认。
  • 发送方维护一个窗口边界 base,窗口范围即 [base, base+N]
  • 接收方维护一个大小为 1 的接收窗口,每当窗口内接受到的数据段接收完成,窗口向前移动,否则丢弃。乱序帧因为不在窗口内,会被直接丢弃。
  • 接收方可以择机返回 ACK(不需要为每个段返回 ACK),譬如,收到了序号为 1~5 的数据段,可以只返回 ACK 5。
  • 发送方接收到 ACK M,就将 base 调整为 M + 1,如果此时发送窗口内所有数据都没有发送过,则直接发送新的数据,否则继续等待新的 ACK。
  • 发送方每次发送数据后重置定时器,如果超时,则重传发送窗口内所有数据段。
  • 如果接收方收到误码帧,序号 X,则发送 ACK (X-1),等待重传。

正常状态下 GBN 的运行图示:

460e2bb558126b4ffbd79dd144f0cee8.gif

丢包后的重传演示 (图中有个小错,接收窗口外的数据帧不会回复 ACK):

db97708044e17e396c8110f0703a6d2f.gif

连续 ARQ 协议的信道利用率

如果每个数据段都返回 ACK,则在理想情况下,GBN 协议的信道利用率为:

\frac{n\cdot t_s}{t_s + RTT}

其中 n 为发送窗口大小。

在累计确认的情况下,理想情况下 GBN 的信道利用率为:

\frac{n\cdot t_s}{n\cdot t_s + RTT}

选择重传协议 SR

选择重传协议是对连续 ARQ 协议的改进。有如下几点不同:

  1. 接收窗口可以大于 1,但小于等于发送窗口。
  2. 发送窗口 base 不随 ACK 移动,而是指向第一个未确认的数据帧。
  3. 发送方可以仅重传出错或超时的数据帧,而不是整个窗口重传。
  4. 接收窗口和发送窗口一般小于等于数据帧最大序号的一半。这是为了确保发送的数据帧序号横跨两个序号周期时,不会互相混淆。

正常状态下 SR 的运行过程:

ad0e0ee2f6930219fc088917fad0aabf.gif

存在丢包时,SR 的运行过程:

3949a02905d88bf8e8e6eb842aa4741c.gif

TCP 协议

TCP 协议规定数据传输的双方维护一个传输控制块 TCB,用于数据传输过程的控制。通常包括:

  • 地址信息(对方的 ip、端口号)
  • 序列号(需要接收的下一个字节在字节流中的编号。用于跟踪字节流传输。)
  • 窗口大小(发送窗口大小、接收窗口大小,用于限制发送速度和接收速度。)
  • 超时和重传信息(重传计时器、往返时间。发送方根据这些信息判断数据是否丢失)
  • 发送和接收缓冲区(缓冲已发送未确认的信息,用于重传;缓冲已接收未校验未或读取的数据,用于校验和应用读取)
  • ...

TCP报文分段

TCP 会主动对数据进行分段,这是为了实现流量控制、拥塞控制和重传。通过控制数据段的长度,可以实现发送速率的动态调控。通过对数据的分段,可以避免发送失败时将全部数据重传,减小重传开销。

最大报文段长度(MSS) 通常受到底层 MTU 的限制,因为需要避免数据段被 IP 层再次分片带来额外开销。

TCP 报文首部

Screenshot_20241105_081832.jpg
名词解释:

  1. 序号占 4 字节,范围是 [0,2^{32}-1],共 2^{32}(即4294967296)个序号。指示的是数据段在完整数据中的位置。TCP是面向字节流的,因此这里的序号是按照字节编号的。
  2. 确认号占 4 字节,是期望收到对方下一个报文段的第一个数据字节的序号。假设已经收到 100 字节,那么回复的确认帧中确认号应为 101。
  3. 数据偏移占 4 位,这个字段实际上是指出TCP报文段的首部长度。
  4. 保留部分占 6 位,为0。用于标志位将来可能的扩展。
  5. 标志位占 6 位,其中
    • URG 是紧急标志位,用于启用紧急指针
    • ACK 是确认标志位,用于启用确认号
    • PSH 是推送标志位,用于通知接收方立即推送缓存给应用;
    • RST 是复位标志位,用于通知接收者连接出现不可逆的错误,需要重新建立连接;
    • SYN 是同步标志位,在请求建立连接、回应请求建立连接的时候置 1。用于告知对方己方选择的初始序号
    • FIN 是结束标志位,在最后一个报文段中置 1。用于请求释放连接。
  6. 窗口占 2 字节,是接收方要求的发送方调整的发送窗口大小。用于流量控制 (例如,接收方的缓冲大小不足时,可以通知发送方减小发送窗口,避免数据丢失) 等。
  7. 校验和占 2 字节,使用伪首部和数据部生成。伪首部的格式和上文 UDP 伪首部的格式相同,但需要将协议类型值的 0x11(UDP的协议类型号) 改为 0x06(TCP的协议类型号),报文长度改为 TCP 报文段的长度。

拥塞控制

互联网的硬件资源并不是无限的。如果短时间内过多的数据被注入到网络中,超过了路由器等通信设备的缓存极限,不得不丢弃收到的网络包,就会陷入无法发送、也无法接收的拥塞状态(特别是对于 TCP 这类需要来回发送信息才释放资源的协议)。
因此,我们需要一种控制技术,防止一次性有过多的数据进入互联网。
TCP 使用四个算法进行拥塞控制:慢开始、拥塞避免、快重传、快恢复。已有文章将算法讲的很清楚,此处贴上链接:
https://blog.csdn.net/m0_37962600/article/details/79993310

三次握手🤝

TCP 建立连接的时候需要发送三个报文段,因此被称为"三次握手"。

三次握手全过程可以概括如下:(1) 主机 P1 向 P2 发送“请求建立连接”的报文段。(2) P2 收到了请求,于是向 P1 发送“确认你的请求,我也请求建立连接”的报文段。(3) P1 收到了确认和请求二合一的报文段,于是申请维护连接的资源,同时回复 P2 “确认你的请求”。(4) P2 收到确认报文段,于是申请维护连接的资源。

然而,尽管请求能得到确认,但确认本身也有可能丢失而无法确认。这就是著名的蓝白军问题,即不存在一种绝对可靠的方法,能够让通信双方同时确认连接已正确地建立。三次握手思想在于,确保了通信双方各自执行了一次:请求连接、确认请求 的过程,在收到第一次确认后,就已经可以认为连接已建立,可以申请资源。

下面是三次握手中报文段的具体内容:
t01fe7146b2fe86372c.webp
SYN、ACK 即同步、确认标志位,seq 是 TCP 头部中的 序号,ack 则是 TCP 头部中的确认号。