计算机网络基础(三) --- TCP/IP网络结构(运输层)

运输层

1. 概述和运输服务

  • 运输层协议为运行在不同主机上的应用进程之间提供了逻辑通信功能 , 运输层协议是在端系统中而不是路由器中实现的, 网络应用程序可以调用多种运输层协议, 如因特网的两种协议: TCP 和 UDP ,每种协议都能为调用的应用程序提供一组不同的运输层服务

复制代码
### 1.1 运输层和网络层的关系 : 分工协作

> * 它们之间是**分工协作、各司其职** 的关系,可以用一个经典的比喻来理解:**送信与送包裹**。
> * **网络层 (Network Layer - IP) - "邮政系统"**
>   * **职责:** 提供**主机到主机** (Host-to-Host)的逻辑通信。它的核心任务是**路由和转发**。
>   * **工作方式**:网络层(以IP协议为代表)只关心如何将一个个独立的IP数据报(Packet)从源主机(例如,你的电脑)通过网络中的路由器,尽力而为地(Best-Effort)传递到目标主机(例如,一个遥远的服务器)。
>
>   * **局限性**:IP协议不关心这个数据报是属于哪个应用程序的。它就像邮政系统,只负责把信件送到一栋大楼(目标主机),但不管这封信是给大楼里的张三(浏览器进程)还是李四(微信进程)。同时,它不保证信件一定送达、不保证送达顺序、也不保证信件完好无损。
>
> * **运输层 (Transport Layer - TCP/UDP) - "大楼里的前台/分发员"**
>
>   * **职责** :提供**进程到进程** (Process-to-Process 或 Application-to-Application)的端到端逻辑通信。它的核心任务是**扩展IP的交付服务**。
>
>   * **工作方式** :运输层位于应用程序和网络层之间。它接收来自不同应用程序的数据,并添加上运输层首部(包含关键信息:**端口号** ),形成**报文段**(Segment)。然后,它将报文段交给网络层去发送。
>
>   * **如何解决网络层的局限性**:
>
>     * **复用 (Multiplexing) 和 分用 (Demultiplexing)** :通过**端口号(Port Number)** 这个标识,运输层可以将来自多个应用程序的数据(复用)通过同一个网络层接口发送出去,也能将接收到的数据准确地分发给正确的应用程序(分用)。这就是"前台"根据信封上的房间号(端口号)把信分发给不同员工(进程)的过程。
>     * **增强服务**:运输层协议(如TCP)可以在网络层提供的不可靠服务之上,提供可靠性保证、流量控制、拥塞控制等高级功能。
> * ****总结关系:****
>   * **网络层是通信的"基础设施"**,负责全局的、主机级别的数据传输。
>   * **运输层是通信的"服务增强者"**,负责局部的、应用级别的数据传输,并在此基础上提供更高质量、更可控的数据传输服务。
>   * 没有网络层,运输层无法实现通信;没有运输层,应用程序无法直接、可靠地使用网络层服务。
复制代码
### 1.2 因特网运输层概述

* 因特网的设计者们深刻地理解上述的分工思想,因此其运输层提供了两种风格迥异的核心协议,以满足不同应用程序的多样化需求。这就好比提供了"顺丰快递"(强调可靠、安全)和"普通信件"(强调快速、简单)两种服务。
*
  > 因特网的运输层协议主要有两个:
  > * **传输控制协议 (TCP - Transmission Control Protocol)**
  >
  > * **用户数据报协议 (UDP - User Datagram Protocol)**

* 下面是一个快速的对比概述:
  *
    >
    > |    特性    |                   **TCP (传输控制协议)**                    |           **UDP (用户数据报协议)**           |
    > |----------|-------------------------------------------------------|---------------------------------------|
    > | **连接性**  | **面向连接的 (Connection-Oriented)**                       | **无连接的 (Connectionless)**             |
    > |          | 在数据传输前需要经过"三次握手"建立连接,传输结束后有"四次挥手"释放连接。                | 无需建立连接,可直接发送数据。                       |
    > | **可靠性**  | **可靠的 (Reliable)**                                    | **不可靠的 (Unreliable)**                 |
    > |          | 通过确认、重传、序号等机制,确保数据无差错、不丢失、不重复且按序到达。                   | "尽力而为"交付,不保证数据一定到达,也不保证顺序。            |
    > | **流量控制** | **有**                                                 | **无**                                 |
    > |          | 通过滑动窗口机制,确保发送方不会因为发送太快而淹没接收方。                         | 发送方以恒定速率发送,不管接收方能否处理。                 |
    > | **拥塞控制** | **有**                                                 | **无**                                 |
    > |          | 通过复杂的算法(如慢启动、拥塞避免)感知网络拥堵并调整发送速率,对Internet整体稳定性至关重要。   | 没有拥塞控制,网络拥堵时可能会加重负担。                  |
    > | **传输单位** | **字节流 (Byte Stream)**                                 | **报文 (Message)**                      |
    > |          | 应用程序交付的数据被视为无结构的字节流,TCP会将其拆分/组合成合适的报文段。               | 应用程序交付的每一个数据块都封装成一个独立的UDP数据报。         |
    > | **头部开销** | **大 (通常20字节)**                                        | **小 (仅8字节)**                          |
    > |          | 首部包含大量用于实现可靠传输和控制机制的字段。                               | 首部非常简单,只有源端口、目的端口、长度和校验和。             |
    > | **典型应用** | Web (HTTP/HTTPS), 电子邮件 (SMTP), 文件传输 (FTP), 远程终端 (SSH) | 域名解析 (DNS), 语音/视频通话 (VoIP), 流媒体, 在线游戏 |

* 为了简化术语, 我们将运输层分组称为报文段, 然而 因特网文献(RFC文档) 也将TCP的运输层分组成为报文段, 而常将UDP 的分组成为数据报, **我们在这个系列的文章将TCP 和 UDP 的分组统称为报文段** , 而**将数据报的称谓留给网络层分组**

2. 多路复用与多路分解

  • 在一台主机上,通常同时运行着多个网络应用程序(如浏览器、微信、音乐播放器)。它们可能同时在使用网络收发数据。

    • 那么问题来了:当主机从网络层收到一个数据报时,它应该如何知道这个数据报是属于浏览器进程的,还是属于微信进程的?

    • 答案就是 :通过运输层的多路分解

    • 反过来:当主机上的多个应用程序都要发送数据时,它们的数据是如何通过同一个网络接口卡(NIC)发送出去的?

    • 答案就是 :通过运输层的多路复用

  • 简单定义:

    • 多路复用 (Multiplexing) :在发送方,运输层从多个不同套接字(Socket)接收应用程序数据,并为每块数据封装上运输层首部信息(主要是端口号),然后将这些报文段传递到网络层的过程。

    • 多路分解 (Demultiplexing) :在接收方,运输层检查报文段中的字段(主要是目的端口号),标识出接收套接字,从而将运输层报文段中的数据定向到正确的套接字的过程。

复制代码
### 2.1 无连接的多路复用和多路分解 (UDP)

> * UDP的多路复用与分解非常简单直接,其socket用一个二元组来标识:**(目的IP地址, 目的端口号)**。
> * **发送方 (多路复用):**
>
>   * 1. 应用程序创建一个UDP套接字。操作系统会为该套接字分配一个源端口号(可以是自动分配的,也可以是应用程序绑定的)。
>   * 2. 应用程序通过该套接字发送数据时,UDP会为数据封装一个首部,其中包含源端口号和目的端口号。
>   * 3. 所有应用程序的UDP报文段都通过同一个"通道"(主机网络层接口)发送出去。
> * **接收方 (多路分解)** :
>   * 1. UDP维护着一个**套接字表**,可以理解为一张简单的清单,记录了本机所有正在监听的UDP套接字及其绑定的端口号。
>   * 2. 当主机收到一个UDP报文段时,UDP检查报文段首部中的**目的端口号**。
>   * 3. UDP将该报文段的数据部分导向到正在**监听该目的端口号**的那个套接字。
>   * **4. 注意**:UDP不关心源地址和源端口号,它只认目的端口号。这意味着,只要目的端口号相同,来自任何源IP和源端口的报文都会被送到同一个套接字。
> * **一个生动的比喻:**   
>   UDP就像一个**大学宿舍楼的公用快递架**。
>
>   * **多路复用**:所有学生(应用程序)都把要寄出的快递(数据报)放在架子上(交给网络层),快递单上写着收件人的地址和宿舍号(目的IP和端口)。
>
>   * **多路分解** :快递小哥把送来的快递放到架子上。学生只根据快递单上的**宿舍号(目的端口)** 来认领自己的快递。他不在乎这个快递是来自北京的妈妈还是上海的朋友(不区分源)。
复制代码
### 2.2 面向连接的多路复用和多路分解 (TCP)

> * TCP的多路分解机制比UDP要精细和复杂得多,这是由其**面向连接** 的特性决定的。一个TCP套接字不是由一个二元组,而是由一个**四元组** 来唯一标识的:  
>   **(源IP地址, 源端口号, 目的IP地址, 目的端口号)**
> * **为什么需要四元组?**   
>   因为TCP是面向连接的。一台服务器(如Web服务器)通常只在一个端口上监听(如80),但却要同时处理成千上万个来自不同客户端的连接。如果只使用目的端口号进行分解,所有客户端的请求都会被导向同一个监听套接字,服务器将无法区分彼此独立的连接。
>
> * **接收方 (多路分解)**:
>
>   * 1. 服务器有一个**欢迎套接字(Welcome Socket)**,它被绑定在某个特定端口(如80)上,专门用于监听新的连接请求。
>   * 2. 当一个客户端发起连接(SYN报文段到达)时,欢迎套接字会接受它,服务器内核会为这个**特定的连接** 创建一个**新的连接套接字(Connection Socket)**。
>   * 3. 此后,所有来自这个客户端(具有特定源IP和源端口)的报文段,在通过IP层交付后,TCP会根据其**四元组**信息,精确地将数据定向到为其创建的那个唯一的连接套接字中。
>   * 4. 因此,服务器上最终会有**一个欢迎套接字** 和**成百上千个活跃的连接套接字**,每个连接套接字都通过四元组与一个客户端连接唯一对应。
> * **发送方 (多路复用)**:
> * 在客户端,一个TCP应用也可能同时建立多个连接(例如,浏览器同时打开多个标签页连接到同一个服务器)。TCP会为每个连接创建不同的套接字。在发送时,数据从不同套接字流出,TCP会为每个报文段封装上对应的源和目的端口号,然后复用到网络层。
>
> * **一个生动的比喻:** TCP就像一个**公司的前台接待**。
>
>   * **欢迎套接字**:前台总机号码(如公司总机:12345678)。任何人打这个号码都会连接到前台。
>
>   * **连接请求**:一个客户(源IP:端口 = 客户A的手机号)打电话到总机,说要联系销售部。
>
>   * **创建新套接字** :前台将电话**转接(Forward)** 给销售部的某位专员张三(创建一个新的连接套接字)。此后,客户A与张三直接通话。
>
>   * **多路分解**:此时,另一个客户B(另一个源IP:端口)也打电话到总机,也要找销售部。前台会把他的电话转接给另一位专员李四(创建另一个新的连接套接字)。
>
>   * **四元组的作用** :这样,虽然所有外部电话都打向同一个总机号(目的IP:80),但公司内部却建立了多条独立的、并发的通话线路。前台/电话系统通过**来电号码(源IP:端口)** 来区分该把电话转给谁。
复制代码
### 2.3 Web 服务器与TCP

* Web服务器是阐述TCP多路复用与多路分解原理的完美例子。
* **场景** :一个Web服务器(IP地址:`192.168.1.1`)运行着HTTP服务,监听**端口80** 。
  > * 1. **初始化** :
  >   * 服务器启动,创建一个**欢迎套接字** ,并将其绑定到`192.168.1.1:80`。这个套接字开始监听来自任何源地址的连接请求。
  >
  > * 2. **客户端连接**:
  >
  >   * **客户端A** (IP: `10.0.0.2`)打开浏览器访问网站。操作系统为浏览器分配一个**临时(ephemeral)端口** ,例如 `49152`。浏览器发起TCP连接到 `192.168.1.1:80`。
  >
  >   * 这个连接请求的报文段包含:
  >
  >     * 源地址:`10.0.0.2:49152`
  >
  >     * 目的地址:`192.168.1.1:80`
  >
  >   * 服务器端的TCP接收到这个SYN报文段。它检查目的端口是80,于是知道这个请求是给HTTP服务的。它接受连接,并**创建一个新的连接套接字** ,专门用于和客户端A `(10.0.0.2:49152)` 通信。
  >
  > * 3. **另一个客户端同时连接**:
  >
  >   * 几乎同时,**客户端B** (IP: `10.0.0.3`)也访问同一网站。其操作系统分配了另一个临时端口 `49153`。它发起连接到 `192.168.1.1:80`。
  >
  >   * 这个连接请求的报文段包含:
  >
  >     * 源地址:`10.0.0.3:49153`
  >
  >     * 目的地址:`192.168.1.1:80`
  >
  >   * 服务器端TCP再次看到目的端口是80,但它发现源地址 `(10.0.0.3:49153)` 与之前为客户端A创建的套接字不同。因此,它会**再创建一个新的连接套接字**,专门用于和客户端B通信。
  >
  > * 4. **多路分解的实现**:
  >
  >   * 现在,服务器上有**三个套接字**:
  >
  >     * 套接字 #1:欢迎套接字,监听 `:80`。
  >
  >     * 套接字 #2:连接套接字,关联四元组 `(10.0.0.2:49152, 192.168.1.1:80)`。
  >
  >     * 套接字 #3:连接套接字,关联四元组 `(10.0.0.3:49153, 192.168.1.1:80)`。
  >
  >   * 当后续的数据报文段从网络到达时,服务器TCP栈会检查报文段的**四元组**。
  >
  >     * 如果是 `(10.0.0.2:49152, 192.168.1.1:80)`,数据被导向套接字 #2。
  >
  >     * 如果是 `(10.0.0.3:49153, 192.168.1.1:80)`,数据被导向套接字 #3。
  >
  >   * 这样,两个客户端虽然连接到服务器的同一个IP和端口,但它们的数据流被完全隔离,互不干扰。Web服务器可以为每个连接套接字单独分配资源(如一个线程或进程),从而实现**并发处理**多个客户端请求。

* **核心要点:**

  > * **​​​​​​​** Web服务器通过**一个固定的端口号**(如80)对外提供服务。
  >
  > * 它利用TCP的**四元组多路分解** 机制,为每个客户端连接创建**独立的通信通道**。
  >
  > * 客户端使用的**临时端口号**是实现这种并发连接的关键,它确保了每个连接的"源IP:源端口"二元组在主机上是唯一的,从而使得四元组在全球范围内唯一标识一个连接。
  >
  > * 这种机制是所有高性能服务器(Web、数据库、游戏等)能够同时服务海量客户端的基石。

3. UDP -- 无连接运输

复制代码
### 3.1 UDP 报文段结构
复制代码
### 3.2 UDP 检验和

4. 可靠数据传输原理

复制代码
### 4.1 构造可靠数据传输协议
复制代码
### 4.2 流水线可靠数据传输协议
复制代码
### 4.3 回退N步
复制代码
### 4.4 选择重传

5. TCP -- 面向连接的运输

复制代码
### 5.1 TCP 连接
复制代码
### 5.2 TCP 报文段结构
复制代码
### 5.3 往返时间的估计与超时
复制代码
### 5.4 可靠数据传输
复制代码
### 5.5 流量控制
复制代码
### 5.6 TCP 连接管理

6. 拥塞控制原理

复制代码
### 6.1 拥塞原因与代价
复制代码
### 6.2 拥塞控制方法

7. TCP拥塞控制

复制代码
### 7.1 公平性
复制代码
### 7.2 网络辅助拥塞控制
  • s
  • s
  • s
  • s
  • s