【网络篇】计算机网络——运输层详述(笔记)
目录
一、运输层
1. 概述
2. 运输层和网络层的关系
3. 运输层协议概述
二、多路复用和多路分解
1. 综述
2. 无连接的多路复用与多路分解(UDP)
3. 面向连接的多路复用与多路分解(TCP)
4. Web 服务器与TCP
三、UDP(无连接运输)
1. 综述
2. UDP 报文段结构
四、TCP(面向连接的运输)
1. TCP 连接概述
2. TCP报文结构
3. TCP 连接管理
(1)连接建立
(2)连接断开
(3)客户端状态转换
(4)服务器端状态转换
一、运输层
运输层位于 应用层 和 网络层之间,是分层的 网络体系结构的 重要部分。该层 为 运行在不同主机上的 应用进程 提供直接的 通信服务起着 至关重要的作用。
1. 概述
运输层 协议为运行 在不同主机上 的应用 进程之间提供了 逻辑通信(logic communica-tion)功能。
从应用程序的 角度看,通过 逻辑通信,运行 不同 进程的 主机好像 直接相连一样;实际上,这些 主机也许 位于 地球的两侧,通过 很多路由器及 多种不同 类型的 链路相连。
应用进程 使用 运输层提供的 逻辑通信功能 彼此 发送报文,而 无须考虑承载 这些报文的 物理基础设施的 细节。
运输层协议是在 端系统中 而不是在 路由器中实现的。
在发送端,运输层将从 发送应用程序进程 接收到的报文转换成 运输层 分组,用 因特网 术语来讲该 分组称为 运输层 报文段(segment)。实现的方法(可能)是将 应用报文 划分为 较小的块,并每块 加上一个 运输层首部以 生成运输层 报文段。
在 发送端 系统中,运输层 将这些报文段 传递给 网络层,网路层 将其封装成 网络层分组(即数据报)并向 目的地 发送。
在接收端,网络层 从数据报中 提取运输层 报文段,并将 该报文段向 上交给运输层。运输层则 处理接收到的 报文段,使该 报文段中的数据 为接收应用 进程使用。
网络应用程序 可以 使用多种的 运输层协议,每种 协议都能为 调用的应用程序 提供一组 不同的 运输层服务。
注意:
网络 路由器仅 作用于该 数据报的 网络层字段;即 它们 不检查封装在 该数据报的 运输层 报文段的字段。
2. 运输层和网络层的关系
在 协议栈中,运输层 刚好位于 网络层之上。网络层 提供了主机之间的 逻辑通信,而 运输层为 运行在不同主机上的 进程之间 提供了 逻辑通信。
这里用一个 家庭类比来 帮助分析 这种差别。
考虑有两个家庭,一家位于美国东海岸,一家位于美国西海岸,每家有12个孩子。东海岸家庭的孩子们是西海岸家庭孩子们的堂兄弟姐妹。
这两个家庭的孩子们喜欢彼此通信,每个人每星期要互相写一封信,每封信都用单独的信封通过传统的邮政服务传送。因此,每个家庭每星期向另一家发送144 封信。
每一个家庭有个孩子负责收发邮件,西海岸家庭是 Ann 而东海岸家庭是 Bill。每星期 Ann 去她的所有兄弟姐妹那里收集信件,并将这些信件交到每天到家门口来的邮政服务的邮车上。当信件到达西海岸家庭时,Ann 也负责将信件分发到她的兄弟姐妹手上。在东海岸家庭中的Bill 也负责类似的工作。
在这个例子中,邮政服务为两个家庭间提供逻辑通信,邮政服务将信件从一家送往另一家,而不是从一个人送往另一个人。在另一方面,Ann 和Bill 为堂兄弟姐妹之间提供了逻辑通信,Ann 和 Bill 从兄弟姐妹那里收取信件或到兄弟姐妹那里 交付信件。注意到从堂兄弟姐妹们的角度来看,Ann 和 Bill 就是邮件服务,尽管他们只是端到端交付过程的一部分(即端系统部分)。
- 应用层报文 = 信封上的字符
- 进程 = 堂兄弟姐妹
- 主机(又称为端系统)= 家庭
- 运输层协议 = Ann 和 Bill
- 网络层协议 = 邮政服务(包括邮车)
值得注意的是,Ann 和 Bill 都是在各自家里进行工作的;例如,他们并 没有参与 任何一个中间邮件中心 对邮件进行分拣,或者 将邮件 从一个邮件中心 送到另一个 邮件中心之类的工作。类似地,运输层协议 只工作在 端系统中。
在 端系统中,运输层协议 将来自 应用进程的报文移动到 网络边缘(即网络层),反过来也是一样,但对 有关这些报文 在网络核心如何移动 并不作任何规定。
事实上,中间 路由器 既不处理 也不识别运输层加在 应用层报文的 任何信息。
现在假定 Ann 和 Bill 外出度假,另外一对堂兄妹(如 Susan 和 Harvey)接替他们的工作,在家庭内部进行信件的收集和交付工作。
不幸的是,Susan 和 Harvey 的收集和交付工作与 Ann 和 Bill 所做的并不完全一样。由于年龄更小,Susan 和 Harvey 收发邮件的次数更少,而且偶尔还会丢失邮件(有时是被家里的狗咬坏了)。因此,Susan 和 Harvey 这对堂兄妹并没有提供与 Ann 和 Bill一样的服务集合(即相同的服务模型)。
与此类似,计算机网络中 可以 安排多种 运输层协议,每种协议为 应用程序 提供不同的 服务模型。Ann 和 Bill 所能提供的 服务明显 受制于 邮政服务所能 提供的服务。例如,如果 邮政服务不能提供在 两家之间 传递邮件 所需时间的 最长期限(例如3天),那么 Ann 和 Bill 就 不可能 保证邮件 在堂兄弟姐妹 之间 传递信件的 最长期限。
与此类似,运输协议 能够 提供的服务 常常 受制于 底层网络层协议的 服务模型。如果 网络层协议 无法为 主机之间 发送的 运输层报文 段提供 时延或 带宽保证的话,运输层 协议 也就 无法为 进程之间发送的 应用程 序报文提供 时延或 带宽保证。
然而,即使 底层网络协议 不能在网络层提 供相应的 服务,运输层协议 也能 提供 某些服务。例如,即使 底层网络协议 是不可靠的,也 就是说网络层协议 会使 分组丢失、篡改和冗余,运输协议 也能为 应用程序提供 可靠的 数据传输服务。
另一点是,即使 网络层 不能保证运输层报文段的 机密性,运输协议 也能使用 加密 来确保 应用程序报文 不被人侵者读取。
3. 运输层协议概述
因特网为 应用层提供了 两种截然不同的 可用运输层协议。这些协议一种是 UDP(用户数据报协议),它为 调用它的 应用程序 提供了一种 不可靠、无连接的服务。另一种是 TCP(传输控制协议),它为 调用它的应用程序 提供了一种 可靠的、面向连接的 服务。
当设计一个 网络应用程序时,该 应用程序的 开发人员在 生成套接字时 必须指定是 选择 UDP 还是选择 TCP。
我们将 运输层分组称 报文段(segment)。将 UDP 的分组称为数据报(data-gram)。
因特网网络层协议有一个名字叫 IP,即 网际协议。IP 为主机之间 提供了 逻辑通信。IP 的服务模型是 尽力而交付服务(best-effort delivery serv-ice)。这意味着 IP 尽它 “ 最大的努力 ” 在通信的主机之间 交付报文段,但 它并不做 任何确保。特别是,它不确保报文段的交付,不保证报文段的按序交付,不保证报文段中数据的完整性。由于这些原因,IP 被称 不可靠服务(unreliable service)。每台主机 至少有一个 网络层地址,即所谓的 IP 地址。
UDP 和 TCP 最基本的 责任是,将两个端系统间IP 的交付服务扩展为运行在端系统上的两个进程之间的交付服务。将主机间交付 扩展到 进程间交付 被称 运输层的多路复用(transport-layer multiplexing)与多路分解(demultiplexing)。UDP 和 TCP 还可以 通过在 其报文段 首部中包括 差错检查字段 而提供 完整性 检查。
进程 到 进程的 数据交付 和 差错检查是 两种最低限度的 运输层服务,也是 UDP 所能提供的仅有的两种服务。特别的,与 IP 一样,UDP 也是一种 不可靠的服务,即 不能保证一 个进程 所发送的数据 能够完整无缺地 到达目的 进程。
另一方面,TCP 为应用程序提供了 几种 附加服务。首先,它提供 可靠数据传输(relia-ble data transfer)。通过 使用流量控制、序号、确认和定时器,TCP 确保正确地、按序地将数据从发送进程 交付给 接收进程。这样,TCP 就将两个 端系统间的不可靠 IP 服务转换成了 一种 进程间的 可靠数据传输服务。
TCP 还提供 拥塞控制(con-gestion control)。拥塞控制 与其说是一种提供给调用它的应用程序的服务,不如说是一种 提供给整 个因特网的 服务,这是一种 带来通用 好处的服务。不太严格地说,TCP 拥塞控制 防止任何一条 TCP 连接用过 多流量来 淹没 通信主机 之间的 链路 和 交换设备。TCP 力求为 每个通过一条 拥塞网络链路的 连接平等地 共享 网络链路 带宽。这 可以 通过调节 TCP 连接的 发送端发送 进网络的 流量速率 来做到。
另一方面,UDP 流量是 不可调节的。使用 UDP 传输的应用程序可以根据 其需要 以其 愿意的任何 速率发送 数据。
二、多路复用和多路分解
1. 综述
在 目的主机,运输层 从紧邻其下的 网络层 接收报文段。运输层 负责将 这些报文段中的 数据交付 给在主机上 运行的适当应用 程序进程。
再来看一个例子。假定你正坐在计算机前下载 Web 页面,同时还在运行一个 FTP 会话 和 两个 Telnet 会话。这样 就有 4 个网络 应用进程 在运行,即两个 Telnet 进程,一个 FTP 进程 和 一个 HTTP 进程。当你的 计算机中的 运输层 从底层的网络层 接收数据时,它需要 将所接收到的 数据定向到这 4 个进程中的一个。现在来 研究这是 怎样完成的。
一个进程(作为网络应用的一部分)有一个 或 多个套接字(socket),它 相当于 从网络向 进程 传递数据 和 从进程向网络传递 数据的 门户。因此,在 接收主机中的 运输层 实际上并 没有直接 将数据 交付给进程,而是 将数据 交给了一个 中间的套接字。
由于 在任一时刻,在 接收主机上 可能有 不止一个套接字,所以 每个套接字都有 唯一的标识符。标识符 的格式 取决于它是 UDP 还是 TCP 套接字。
现在 考虑 接收主机 怎样将一个 到达的 运输层报文段 定向到 适当的 套接字。为此目的,每个运输层报文段中 具有 几个字段。在接收端,运输层 检查 这些字段,标识出 接收套接字,进而将 报文段定向到 该套接字。
将 运输层报文段中的 数据交付到 正确的套接字的 工作称为 多路分解(demultiplexing)。
在源主机 从不同套接字中 收集数据块,并为 每个数据块 封装上 首部信息(这将在 以后用于分解)从而 生成报文段,然后 将报文段传递到 网络层,所有 这些 工作称为多路复用(multiplexing)。
上图 中间的 那台主机的 运输层必须 将 从其下的网络层收到的 报文段分解 后交给 其上的 P1 或 P2 进程;这一过 程是 通过将 到达的报文段 数据 定向到对应 进程的套接字 来完成的。
中间主机中的 运输层也 必须收集 从这些套接字 输出的 数据,形成 运输层 报文段,然后 将其向下传 递给 网络层。
那它们在 主机中 实际是怎样工作的 ?从上述中运输层多路复用要求为:① 套接字有唯一标识符;② 每个报文段有特殊字段来 指示该报文段 所要交付到的 套接字。
这些特殊字段是 源端口号字段(source port number field)和 目的端口号字段(destination port number field)。端口号 是一个 16 比特的数,其大小在 0~65535 之间。
0~1023 范围的端口号称为 周知端口号(well-known portnumber),是受限制的,这是指它们 保留给诸如 HTTP(它使用端口号 80)和 FTP(它使用端口号 21)之类的周 知应用层 协议来使用。当我们 开发一个新的 应用程序时,必须为 其分配一个 端口号。
2. 无连接的多路复用与多路分解(UDP)
(1)当我们使用 socket()函数 创建一个 UDP 套接字时,运输层 自动地为该 套接字 分配一个 端口号。特别是,运输层 从范围 1024~65535 内分配一个 端口号,该 端口号 是当前 未被该主机 中 任何其他 UDP 端口 使用的 号。
(2)另外一种方法是,在 创建一个 套接字 后,我们 能够 通过套接字 bind()方法 为这个 UDP 套接字 关联一个 特定的 端口号。
(3)如果 应用程序开发者 所编写的 代码实现 的是一个 “ 周知协议 ” 的服务器端,那么 开发者 就必须 为其分配 一个相应的 周知 端口号。
通常,应用程序的客户端 让运输层自动地(并且是透明地)分配 端口号,而 服务器端 则分配一个特 定的端口号。
假定在 主机 A 中的一个 进程 具有 UDP 端口 19157,它要 发送一个 应用程序 数据块 给 位于 主机 B 中的 另一进程,该进程 具有 UDP 端口 46428。
主机 A 中的 运输层 创建一个 运输层 报文段,其中 包括应用 程序数据、源端口号(19157)、目的 端口号(46428)和 两个其他值。
然后,运输层 将得到的 报文段 传递到 网络层。网络层 将该报文段 封装到一个 IP 数据报中,并 尽力而为地 将报文段 交付给接 收主机。
如果该 报文段到达接收 主机 B,接收主机 运输层 就检查该 报文段中的 目的 端口号(46428)并将 该报文段交 付给 端口号 46428 所标识的 套接字。
注意:
① 主机 B 能够 运行多个进程,每个 进程有自己的 UDP 套接字 及 相应的端 口号。当UDP 报文段 从 网络 到达时,主机 B 通过 检查该 报文段中的 目的端口号,将 每个报文段 定向(分解)到 相应的 套接字。
② 一个 UDP 套接字是 由一个 二元组 全面标识的,该 二元组 包含一个 目的 IP 地址和一个 目的 端口号。因此。如果两个 UDP 报文段 有不同的 源 IP 地址 或源端口号,但 具有相同的目的 IP 地址 和 目的端口号,那么这 两个报文 段 将通 过相同的 目的套接字 被 定向到 相同的 目的进程。
源端口号的 用途 是什么呢?
在 A 到 B 的报文段 中,源端口号 用作 “ 返回地址 ” 的一部分,即当 B 需要 回发一个 报文段给 A 时,B 到 A 的报文段 中的 目的端口号 便从 A 到 B 的报文段 中的 源端口号中 取值。(完整的返回地址是 A 的 IP 地址 和 源端口号。)
3. 面向连接的多路复用与多路分解(TCP)
TCP 套接字 和 UDP 套接字 之间的一个 细微差别是,TCP 套接字 是由 一个 四元组(源 IP 地址,源端口号,目的 IP 地址,目的端口号)来标识的。因此,当一个 TCP 报文段 从 网络 到达一台主机 时,该主机 使用 全部 4 个值 来将 报文段定向(分解)到 相应的套接字。
与 UDP 不同的是,两个具有 不同源 IP 地址 或 源端口号的 到达 TCP 报文段 将被 定向到 两个不同的 套接字,除非 TCP 报文段 携带了初 始创建连接的 请求。
举个 TCP 客户-服务区编程 的例子:
- TCP服务器应用程序有一个 “ 欢迎套接字 ” ,它在 12000 号 端口上 等待来自 TCP 客户的 连接 建立请求。
- TCP 客户使用 socket()函数 创建一个 套接字并 使用 connect()函数 发送一个 连接 建立请求 报文段。
- 一条 连接建立 请求 只不过 是一个 目的端口号 为 12000,TCP 首部的 特定 “ 连接建立位 ” 置位的 TCP 报文段。这个 报文段 也包含 一个由 客户选择 的 源端口号。
- 当 运行服务器 进程的 计算机 的主机操作系统 接收到 具有 目的端口 12000 的人连 接请求 报文段后,它就 定位 服务器进程,该进程 正在 端口号 12000 等待 接受连接。该 服务器 进程则 创建一个新的 客户端套接字。
- 该 服务器的 运输层还 注意到 连接请求报文段 中的 下列 4 个值:① 该报文段中的源端口号;② 源主机IP 地址;③ 该报文段中的 目的端口号;④ 自身的 IP 地址。新 创建的连接 套接字通过这 4 个值来 标识。所有 后续到达 的 报文段,如果 它们的 源端口号、源主机 IP 地址、目的端口号 和 目的 IP 地址 都与这 4 个值匹配,则 被分解到 这个套接字。
- 随着 TCP 连接 完成,客户 和 服务器 便可相 互发送 数据了。
服务器主机 可以 支持很多 并行的 TCP 套接字,每个 套接字 与 一个进程 相联系,并 由 其四元组 来标识 每个套接字。
当一个 TCP 报文段 到达主机 时,所有 4 个字段(源 IP 地址,源端口,目的 IP 地址,目的端口)被用来 将报文段 定向(分解)到相应的 套接字。
上图中 主机 C 向 服务器 B 发起了两个 HTTP 会话,主机 A 向 服务器 B 发起了一个 HTTP 会话。主机 A 与主机 C 及 服务器 B 都有自己 唯一的 IP 地址,它们 分别是 A、C、B。
主机 C 为其两个 HTTP 连接 分配了 两个 不同的 源端口号(26145 和 7532)。因为 主机 A 选择 源端口号时 与主机 C 互不相干,因此 它也可以 将源端口号 26145 分配给其 HTTP 连接。服务器 B 仍然能够 正确地 分解 这两个 具有相同 源端口号 的连接,因为这 两条连接 有不同的 源 IP 地址。
4. Web 服务器与TCP
考虑一台运行 Web 服务器的主机,例如在 端口 80 上运行一个 Apache Web 服务器。
当客户(如浏览器)向 该服务器 发送报文段 时,所有 报文段的 目的端口都 将为 80。特别 是,初始连接 建立报文段 和 承载 HTTP 请求的 报文段都有 80 的 目的端口。该服务器 能够 根据源 IP 地址 和 源端口号 来 区分来自不同客户的 报文段。
上图显示了一台 Web 服务器 为 每条连接 生成一个 新进程。每个 这样的 进程 都有 自己的 连接 套接字,通过这些套接字可以收到 HTTP 请求 和 发送 HTTP 响应。
然而,连接 套接字 与 进程之间 并非 总是有着 一一对应的 关系。事实上,当今 的 高性能 Web 服务器 通常只 使用一个进程,但是为 每个新的客户连接 创建一个 具有 新连接套接字的 新线程。对于 这样一台服务器,在 任意给定的 时间内都 可能有(具有不同标识的)许多 连接 套接字连接到 相同的进程。
如果 客户 与 服务器 使用 持续 HTTP,则 在整条 连接持续 期间,客户 与 服务器 之间经由 同一个服务器 套接字 交换 HTTP 报文。
然而,如果 客户 与 服务器 使用 非持续 HTTP,则对 每一对 请求 / 响应 都创建一个 新的 TCP连接并在随后关闭,因此 对每一对 请求 / 响应 创建一个 新的套接字 并在 随后关闭。这种 套接字的 频繁创建 和 关闭会 严重地 影响一个 繁忙的 Web 服务器 的性能(尽管有 许多 操作 系统技巧可用来 减轻这个 问题的影 响)。
三、UDP(无连接运输)
1. 综述
UDP 只是做了 运输协议 能够做的 最少工作。除了 复用 / 分解功能 及 少量的 差错检测 外,它几乎没有对 IP 增加别的 东西。
UDP 从应用 进程得到 数据,附加上 用于 多路复用 / 分解服务 的 源和目的 端口号字段,以及 两个其他的 小字段,然后 将形成的 报文段交给 网络层。网络层将 该运输层报文段 封装 到一个 IP 数据报中,然 后尽力而为地 尝试将此报文段 交付给 接收主机。如果 该报文段 到达接收 主机,UDP 使用目的端口号 将报文段中 的数据 交付给正确的 应用进程。
值得注意的是,使用 UDP 时,在 发送报文段 之前,发送方 和 接收方的 运输层 实体 之间 没有握手。正因为如此,UDP 被称为是无连接的。
DNS 是一个通常使用 UDP 的应用层协议的例子。
当一台 主机中的 DNS 应用程序 想要进行 一次 查询时,它 构造了一个 DNS 查询报文 并将其交给 UDP。无须 执行任何 与 运行在目的端系统 中的 UDP 实体 之间的握手,主机端的 UDP 为 此报文添加 首部字段,然后 将形成的报文段 交给 网络层。
网络层 将此 UDP 报文段 封装进一个 IP 数据报 中,然后 将其 发送给一个 名字 服务器。在 查询主机中的 DNS 应用程序 则 等待对 该查询的 响应。
如果 它没有 收到 响应(可能是由于底层网络丢失了查询或响应),则要么试图向 另一个 名字服务器 发送 该查询,要么 通知调用 的 应用程序它 不能 获得响应。
2. UDP 报文段结构
应用层 数据 占用 UDP 报文段的数据字段。例如,对于 DNS应用,数据字段要么 包含一个 查询 报文,要么 包含一个响应报文。
UDP 首部只有 4 个字段,每个 字段由 两个字节组成。通过 端口号可以 使目的 主机将 应用数据交给 运行在 目的端系统中 的 相应进程(即 执行 分解功能)。
长度字段 指示了在 UDP 报文段中 的 字节数(首部 加数据)。因为 数据字段的 长度 在一个 UDP 段中 不同于在 另一个段中,故 需要一个 明确的长度。
接收方 使用检验和来 检查在该报文段中 是否出现了差 错。
四、TCP(面向连接的运输)
1. TCP 连接概述
TCP 被称为是 面向连接的(connection-oriented),这是因为在 一个应用 进程可以 开始向另一个应用进程发送数据之前,这 两个进程必须先相互 “ 握手 ” ,即 它们必须 相互发送 某些 预备报文段,以 建立确保数据传输的 参数。作为 TCP 连接建立的 一部分,连接的 双方 都将 初始化与 TCP 连接相关的 许多 TCP 状态变量。
这种 TCP “ 连接 ” 不是一条像在 电路交换网络中的 端到端 TDM 或 FDM 电路。相反,该 “ 连接 ” 是一条 逻辑连接,其 共同状态仅保留在 两个通信端系统的 TCP 程序中。由于 TCP 协议只在端系统 中运行,而 不在中间的 网络元素(路由器 和 链路层交换机)中运行,所以 中间的网络元素不会维持 TCP 连接状态。事实上,中间路由器对 TCP连接完会视而不见,它们看到的是数据报 而不是连接。
TCP 连接总是 点对点(point-to-point)的,即在 单个发送方 与 单个接收方之间的 连接。所谓 “多播”,即 在一次发送操作中,从 一个发送方 将 数据传送给 多个接收方,这种情况对 TCP 来说是不可能的。对于 TCP 而言,两台主机 是一对,而 3 台主机则太多了。
现在来看看 TCP 连接是怎样建立的。
假设运行在某台主机上的一个进程(客户进程)想与 另一台主机上的一个 进程(服务器进程)建立 一条连接。该 客户应用进程首先使用 connect()函数通知 客户运输层,它想 与 服务器上的 一个 进程建立一条连接。
客户上的 TCP 便开始 与 服务器上的 TCP 建立一条 TCP 连接。客户 首先 发送一个 特殊的TCP 报文段,服务器 用 另一个特殊的 TCP 报文段来 响应,最后,客户再 用第 三个特殊报文段 作为响应。
前两个报文段不承载 “ 有效载荷 ” ,即 不包含 应用层数据;而 第三个报文段 可以 承载有效 载荷。由于 在这两台主机之间 发送了 3 个报文段,所以 这种连接 建 立过程常被称为 三次握手(three-way handshake)。
一旦建立起一条 TCP 连接,两个应用 进程之间就 可以相互发送数据了。
现在考虑一下 从客户进程向 服务器进程 发送数据的情况。
客户进程 通过套 接字(该进程之门)传递数据流。数据 一旦 通过该门,它就由 客户中 运行的 TCP 控制了。如上图所示,TCP 将这些数据 引导到 该连接的 发送缓存(send buffer)里,发送缓存是 发起三次握手期间设置的 缓存之一。
接下来 TCP 就会不时从发送缓存里 取出一块 数据,并将 数据传递到 网络层。TCP 可从 缓存中取出 并放入 报文段中的 数据数量 受限于最大报文段长度(Maximum Segment Size,MSS)。MSS 通常 根据最初确定的 由本地 发送主机 发送的 最大链路层帧长度(即所谓的 最大传输单元(Maximum Transmission Unit, MTU))来设置。设置该 MSS 要保证一个 TCP 报文段(当封装在一个 IP 数据报中)加上 TCP/IP 首部长度(通常 40 字节)将适合 单个 链路层帧。
TCP 为每块客户数据配上一个 TCP 首部,从而形成多个 TCP 报文段(TCP segment)。这些报文段被 下传给网络层,网络层 将其 分别封装在 网络层 IP 数据报中。然后这些 IP 数据报被 发送到网络中。
当 TCP 在另一端 接收到一个 报文段后,该报文段的数据就被 放人该 TCP 连接的 接收缓存 中,如上图中所示。应用程序 从此缓存中 读取数据流。
2. TCP报文结构
TCP 报文段 由首部字段 和 一个数据字段 组成。
数据字段 包含一块 应用 数据。其中 MSS 限制了 报文段数据字段 的 最大长度。当 TCP 发送一个 大文件,TCP 通常是 将该文件 划分成 长度 MSS 的若干块(最后一块 除外,它通常 小于 MSS)。然而,交互式应用 通常 传送 长度小于 MSS 的 数据块。
与 UDP 一样,首部 包括源 端口号 和 目的 端口号,它 被用于 多路复用 / 分解 来自 或 送到上层 应用的数 据。另外,同 UDP一样,TCP 首部也 包括 检验 和 字段(checksum field)。
3. TCP 连接管理
(1)连接建立
来观察一下一条TCP 连接是如何建立的。假设运行在一台主机(客户)上的一个进程想与另一台主机(服务器)上的一个进程建立一条连接。
客户应用 进程 首先 通知客户 TCP,它想建立一个 与服务器上 某个进程之间的 连接。客户中的 TCP 会用 以下方式与服务器中的 TCP 建立一条 TCP 连接:
第一步:客户端的 TCP 首先向服务器端的 TCP 发送一个 特殊的 TCP 报文段。该报文段中不包含 应用层数据。但是在 报文段的首部中的一个标志位(即 SYN 比特)被置 1。因此,这个 特殊报文段被称 SYN 报文段。另外,客户会随机地 选择一个 初始序号(client_isn),并将 此编号放置于该起始的 TCP SYN 报文段的 序号字段中。该 报文段会被 封装在一个 IP 数据报 中,并发送给 服务器。
第二步:一旦包含 TCP SYN 报文段的 IP 数据报 到达服务器 主机(假定它的确到达了!),服务器会 从该数据报中 提取出 TCP SYN 报文段,为该 TCP 连接 分 配 TCP 缓存 和 变量,并向该客户 TCP 发送 允许连接的 报文段。这个允许 连接的 报文段 也不包含 应用层数据。但是,在 报文段的 首部却包含 3 个重要的 信息。首先,SYN 比特被置 为 1。其次,该 TCP 报文段首部的 确认号 字段 被置为 client_isn +1。最后,服务器 选择自己的 初始序号(server_isn),并将其放置到 TCP 报文段 首部的序号 字段中。这个 允许连接的 报文段 实际 上表明了:“ 我收到了你发起建立连接的 SYN 分组,该分组 带有 初始序号 client_isn。我 同意 建立该 连接。我 自己的 初始序号是 server_isn。” 该允许连接的 报文段被称为 SYNACK 报文段(SYNACK segment)。
第三步:在收到 SYNACK 报文段后,客户也要 给该连接 分配缓存 和 变量。客户主机 则 向服务器 发送另外一个 报文段;这 最后一个报文段 对服务器的 允许连接的 报文段 进行了 确认(该客户通过将值 server_isn +1 放置到 TCP 报文段首部的 确认字段中来 完成此项 工作)。因为连接已 经建立了,所以该 SYN 比特被 置 0。
该 三次握手的 第三个阶段 可以在报文段负载 中携 带客户到服务器的 数据。以后 每一个报文段中,SYN 比特都将被 置为 0。
(2)连接断开
参与一条 TCP 连接的 两个进程中的 任何一个 都能终止 该连接。当 连接结束后,主机 中的 “ 资源 ”(即缓存和变量)将 被释放。
举个例子,假设某客户打算关闭连接。
客户 应用进程 发出一个 关闭连接 命令。这会引起客户 TCP 向服务器 进程 发送一个 特殊的TCP 报文段。这个特的 报文段 让其首部中 的一个 标志位即 FIN 比特被 设置 1。
当服 务器接收到 该报文段 后,就向发送方回送一个 确认 报文段。然后,服务器发送它自己的 终止报文段,其 FIN 比特被置 为 1。
最后,该客户 对 这个服务器的 终止报文段 进行确认。此时,在 两台主机上 用于 该连接的 所有资源 都被 释放了。
(3)客户端状态转换
在一个 TCP 连接的 生命周期 内,运行在 每台主机中的 TCP 协议 在各种 TCP 状态(TCP state)之间变迁。
- 客户 TCP开始时处于 CLOSED(关闭)状态。
- 客户的 应用程序发起一个 新的 TCP 连接。这引起客户 中的 TCP 向服务器中的 TCP 发送一个 SYN 报文段。在发送过 SYN 报文段后,客户 TCP 进入了 SYN_SENT 状态。
- 当客户 TCP 处在 SYN_SENT 状态时,它 等待 来 自服务器 TCP 的 对 客户所发报文段 进行 确认且 SYN 比特被 置为 1 的一个 报文段。收到 这样 一个报文段 之后,客户 TCP 进入 ESTABLISHED(已建立)状态。
当处在 ESTABLISHED 状态时,TCP 客户就能发送 和接 收包含 有效载荷 数据(即 应用层产生的数据)的 TCP 报文段了。
假设客户 应用程序决 定要 关闭该连接。(服务器 也能 选择 关闭该连接)
- 这引起客户 TCP 发送一个带有 FIN 比特被 置为 1 的 TCP 报文段,并进入 FIN_WAIT_1 状态。
- 当处在 FIN_WAIT_1 状态时,客户 TCP 等待一个 来自服务器的 带有 确认的 TCP 报文段。
- 当 它收到该 报文段时,客户 TCP 进入 FIN_WAIT_2状态。
- 当处在 FIN_WAIT_2 状态时,客户 等待来自 服务器的 FIN 比特 被置为 1 的 另一个 报文段;当收到该 报文段 后,客户 TCP 对服务器的 报文段 进行确认,并进人 TIME_WAIT状态。
- 假定 ACK 丢失,TIME_WAIT 状态使 TCP 客户 重传最后的 确认报文。在 TIME_WAIT 状态中 所消耗的时间 是 与 具体实现 有关的,而典型的值是 30秒、1分钟 或 2分钟。经过 等待后,连接 就正式关闭,客户端 所有资源(包括端口号)将 被释放。
(4)服务器端状态转换
假设客户开始连接拆除。
相关文章:

【网络篇】计算机网络——运输层详述(笔记)
目录 一、运输层 1. 概述 2. 运输层和网络层的关系 3. 运输层协议概述 二、多路复用和多路分解 1. 综述 2. 无连接的多路复用与多路分解(UDP) 3. 面向连接的多路复用与多路分解(TCP) 4. Web 服务器与TCP 三、UDP&#x…...

用java编写飞机大战
游戏界面使用JFrame和JPanel构建。背景图通过BG类绘制。英雄机和敌机在界面上显示并移动。子弹从英雄机发射并在屏幕上移动。游戏有四种状态:READY、RUNNING、PAUSE、GAMEOVER。状态通过鼠标点击进行切换:点击开始游戏(从READY变为RUNNING&am…...

java Map中get方法爆错NullPointerException
代码如下: public class Hello {public static void main(String[] args) {Map<Integer,Integer> map new HashMap<>();map.put(2,1);int i map.get(1); System.out.println(i);} }运行出错,看代码很明显是get到一个不存在map的值&#x…...

ElasticSearch备考 -- Multi field
一、题目 Create the index hamlet_2 with one primary shard and no replicas Copy the mapping of hamlet_1 into hamlet_2, but also define a multi-field for speaker. The name of such multi-field is tokens and its data type is the (default) analysed string Reind…...

刷题 图论
面试经典 150 题 - 图 200. 岛屿数量 dfs 标记 visited class Solution { public:// dfs 染色const int direction[4][2] {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};void dfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x…...

基于JAVA的鲜花商城管理系统(源码+定制+讲解)鲜花商城管理系统、鲜花商城管理平台、鲜花商城信息管理、鲜花商城系统开发与应用、鲜花在线商城管理系统
博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…...

深圳大学-Java程序设计-选实验1 基础知识练习
实验目的与要求: 实验目的:掌握Java程序设计开发环境的搭建,编写简单Java Project,掌握编译、运行等基本步骤和命令。 实验要求: (1).下载、安装"Java SE Development Kit 20.0.2"最新的版本,需…...

第 33 章 Ajax
第 33 章 Ajax 1.XMLHttpRequest 2.GET 与 POST 3.封装 Ajax 2005 年 Jesse James Garrett 发表了一篇文章,标题为:“Ajax:A new Approach to Web Applications”。他在这篇文章里介绍了一种技术,用他的话说,就叫&…...

LeetCode 209 Minimum Size Subarray Sum 题目解析和python代码
题目: Given an array of positive integers nums and a positive integer target, return the minimal length of a subarray whose sum is greater than or equal to target. If there is no such subarray, return 0 instead. Example 1: Input: target 7, nu…...

C# 入坑JAVA 潜规则 注解 列表 listMch,该列表存储了一个映射(Map)的集合 等 入门系列3
java 项目结构 文件说明 潜规则 java入门-CSDN博客 C# 入坑JAVA 潜规则 大小写敏感文件名和类名 枚举等 入门系列2-CSDN博客 java注解 好像和C# 特性 差不多 Data Builder NoArgsConstructor AllArgsConstructor 在Java中,Data、Builder、NoArgsConstructor和Al…...

2024年9月个人工作生活总结
本文为 2024年9月工作生活总结。 研发编码 vuepress构建的几个问题 某vuepress项目,是我在3年多以前自行构想自行着手搞的,主要用于将一些常用的数据文件(markdown样式)渲染成html网页文件,在自建服务程序里开启访问…...

JVM有哪些参数以及如何使用
JVM(Java虚拟机)参数用于调整和优化Java应用程序的性能和行为。这些参数主要分为标准参数、非标准参数(以-X开头)和高级参数(以-XX开头)。以下是一些常见的JVM参数及其使用方法: 标准参数 -se…...

STM32编码器接口解析及抗噪声措施探讨
1. 引言 在现代控制系统中,编码器扮演着非常重要的角色。它就像一个精密的测量工具,可以告诉我们机械部件的位置和运动状态。在STM32微控制器中,编码器接口可以轻松地与各种编码器连接,实现精确的控制。我将在这里探讨STM32编码器…...

微软发布Windows 11 2024更新,新型Copilot+ AI PC功能亮相
前言 微软在Windows 11的2024更新中加强了对人工智能的应用,推出了新功能Copilot。 此次更新的版本号为26100.1742,Copilot将首先在Windows Insider中推出,计划于11月向特定设备和市场推广,用户需开启“尽快获取最新更新”选项以…...

鹏哥C语言68-70---位操作符+单目操作符+关系操作符
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <time.h> //--------------------------------------------------------------------------------------------------------4.位操作符 // &----按(2进制…...

showdoc二次开发
showdoc用的vue版本老,需要安装老版本nodejs,比如node 14.21.3 win32-x64-93_binding.node问题 https://github.com/sass/node-sass/releases 下载 web_src\node_modules\node-sass\vendor\win32-x64-93 下面重命名为binding.node 代理到php后端&…...

力扣16~20题
题16(中等): 思路: 双指针法,和15题差不多,就是要排除了,如果total<target则排除了更小的(left右移),如果total>target则排除了更大的(rig…...

Pikachu-Sql-Inject -基于boolian的盲注
基于boolean的盲注: 1、没有报错信息显示; 2、不管是正确的输入,还是错误的输入,都只显示两种情况,true or false; 3、在正确的输入下,输入and 1 1/and 1 2发现可以判断; 布尔盲注常用函数&…...

最后30天,你的系统集成项目管理工程师备考进度到哪儿了?
十一长假归来好! 此次归来之后,2024年下半年软考倒计时就从4字头切换到了3字头,今天距离考试还有32天! 那么问题来了,临近考试还有30天左右的时候,你的备考进度到哪里了呢? 其实无论目前你的实际…...

网络安全事件的发生,主要原因是什么
网络安全事件的发生,主要原因涉及多个方面,包括技术漏洞、人为因素、经济利益驱动、恶意软件和病毒威胁、社会工程学攻击、内部人员恶意行为、供应链安全问题以及法律法规的不完善等。以下是对这些原因的详细分析: 技术漏洞: 软件…...

【leetcode】274.H指数
为了方便,将 citations 记为 cs。 所谓的 h 指数是指一个具体的数值,该数值为“最大”的满足「至少发表了 x 篇论文,且每篇论文至少被引用 x 次」定义的合法数,重点是“最大”。 用题面的实例 1 来举个 🌰࿰…...

1.Python 引入(字面量、注释、变量、数据类型、数据类型转换、标识符、运算符、字符串扩展)
一、字面量 1、基本介绍 在代码中,被写直接下来的、不需要通过变量存储的值,称之为字面量 2、常用值类型 类型说明数字(Number)整数(int),例如:10、-10浮点数(float&…...

【AI知识点】梯度消失(Vanishing Gradient)和梯度爆炸(Exploding Gradient)
梯度消失(Vanishing Gradient) 和梯度爆炸(Exploding Gradient) 是神经网络训练中的常见问题,特别是在深层神经网络(DNN)或递归神经网络(RNN)中。这两者主要与反向传播算…...

在 ArkTS 网络请求中,重新封装一下 http 模块
在ArkTS中,重新封装http模块可以提供一个更简洁、更易于使用的API,同时隐藏底层细节,使开发者能够更专注于业务逻辑。以下是一个简单的示例,展示了如何重新封装鸿蒙系统的kit.NetworkKit中的http模块: // 创建一个新的…...

Microsoft 更新 Copilot AI,未來將能使用語音並看到你瀏覽的網頁
不過受到 Recall 事件的影響,更新的推出將更緩慢謹慎。 Microsoft 也同步對其網頁版及行動版的 Copilot AI 進行大改版。這主要是為網頁版換上了一個較為簡單乾淨的介面,並增加了一些新的功能,像是 Copilot Voice 能讓你與 AI 助手進行對話式…...

系统架构设计师-论文题(2021年下半年)
1.试题一 论面向方面的编程技术及其应用针对应用开发所面临的规模不断扩大、复杂度不断提升的问题,面向方面的编程Aspect Oriented Programming,AOP技术提供了一种有效的程序开发方法。为了理解和完成一个复杂的程序,通常要把程序进行功能划分和封装。一…...

selenium的webdriver常用方法和属性介绍(2)
selenium的webdriver介绍 从selenium导入webdriver模块,在pycharm中跳转webdriver模块的__init__.py文件,内容如图所示:从selenium包的子目录中导入了很多模块并做了重命名,用于支持如下 Chrome/Edge/Ie/Firefox/Safari浏览器。 使…...

73.【C语言】C/C++的内存区域划分
目录 1.内存里的几个区域 2.示意图 3.解释 1.内存里的几个区域 除了耳熟能详的栈区,堆区,静态区,还有内核空间,内存映射段,数据段,代码段 2.示意图 3.解释 栈区(stack area):局部变量,函数参数,返回数据,返回地址 内存映射段:将文件映射到内存 映射的含义: 如果看过李忠…...

k8s 中存储之 hostPath 卷
目录 1 hostPath 卷介绍 2 hostPath 卷实际应用操作 2.1 创建 pod 资源类型 2.2 修改清单文件增加 hostPath 对应的参数配置 2.3 查看是否创建 卷 和 pod 2.4 创建发布文件测试是否正常访问 1 hostPath 卷介绍 EmptyDir中数据不会被持久化,它会随着Pod的结束而销…...

Cherno游戏引擎笔记(73~90)
------- scene viewport ---------- 》》》》做了两件事:设置视口和设置相机比例 》》》》为什么要设置 m_ViewportSize 为 glm::vec2 而不是 ImVec2 ? 因为后面需要进行 ! 运算,而 ImVec2 没有这个运算符的定义,只有 glm::vec2 有这个运算…...