当前位置: 首页 > news >正文

【运输层】传输控制协议 TCP

目录

1、传输控制协议 TCP 概述

(1)TCP 的特点

(2)TCP 连接中的套接字概念

2、可靠传输的工作原理

(1)停止等待协议

(2)连续ARQ协议

3、TCP 报文段的首部格式

(1)填充字段选项的说明


1、传输控制协议 TCP 概述

(1)TCP 的特点

        (1)TCP 是面向连接的运输层协议。这就是说,应用程序在使用 TCP 协议之前,必须先建立 TCP 连接。在传送数据完毕后,必须释放已经建立的 TCP 连接。

        (2)每一条 TCP 连接只能有两个端点(endpoint),每一条 TCP 连接只能是点对点的(一对一)。

        (3)TCP 提供可靠交付的服务。通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达。

        (4)TCP 提供全双工通信。TCP 允许通信双方的应用进程在任何时候都能发送数据。TCP 连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送时,应用程序在把数据传送给 TCP 的缓存后,就可以做自己的事,而 TCP 在合适的时候把数据发送出去。在接收时,TCP 把收到的数据放入缓存,上层的应用进程在合适的时候读取缓存中的数据。

        (5)面向字节流。TCP 中的“流”(stream)指的是流入到进程或从进程流出的字节序列。“面向字节流”的含义是:虽然应用程序和 TCP 的交互是一次一个数据块(大小不等),但 TCP 把应用程序交下来的数据仅仅看成是一连串的无结构的字节流。TCP 并不知道所传送的字节流的含义。

        从上图可看出,TCP 和 UDP 在发送报文时所采用的方式完全不同。TCP 并不关心应用进程一次把多长的报文发送到 TCP 的缓存中,而是根据对方给出的窗口值和当前网络拥塞的程度,来决定一个报文段应包含多少个字节。如果应用进程传送到 TCP 缓存的数据块太长,TCP就可以把它划分为短一些的数据块再传送。如果应用进程一次只发来一个字节,TCP 也可以等待积累足够多的字节后再构成报文段发送出去。//UDP发送的报文长度是应用进程给出的,有长度限制

(2)TCP 连接中的套接字概念

        前面已经讲过,每一条 TCP 连接有两个端点。那么,TCP 连接的端点是什么呢?

        它既不是主机(IP 地址),也不是应用进程(端口号),TCP 连接的端点叫作套接字(socket)或插口。根据 RFC 793 的定义:端口号拼接到 IP 地址即构成了套接字。因此,套接字的表示方法是在点分十进制的 IP 地址后面写上端口号,中间用冒号或逗号隔开。例如,若 IP 地址是 192.3.4.5 而端口号是 80,那么得到的套接字就是 192.3.4.5:80。//套接字的概念

套接字socket = (IP地址:端口号)

2、可靠传输的工作原理

        我们知道,TCP 发送的报文段是交给 IP 层传送的。但 IP 层只能提供尽最大努力服务,也就是说,TCP下面的网络所提供的是不可靠的传输。

        那么,怎么样才能使得两个运输层之间的通信变得可靠呢?

        理想的传输条件有以下两个特点:

  1. 传输信道不产生差错。
  2. 不管发送方以多快的速度发送数据,接收方总是来得及处理收到的数据。

        在这样的理想传输条件下,不需要采取任何措施就能够实现可靠传输。

        然而实际的网络都不具备以上两个理想条件。所以我们需要使用一些可靠的传输协议,当
出现差错时让发送方重传出现差错的数据,同时在接收方来不及处理收到的数据时,及时告诉发送方适当降低发送数据的速率。这样一来,本来不可靠的传输信道就能够实现可靠传输了。//在不理想的传输条件下需要进行差错校验+拥塞控制

(1)停止等待协议

        “停止等待”就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组。

        1.1无差错的情况

        如下图,A 发送分组 M1,发送完后就暂停发送,等待 B 的确认。B 收到了 M1,就向 A 发送确认。A 在收到了对 M1 的确认后,就再发送下一个分组 M2。同样,在收到 B 对 M2 的确认后,再发送 M3。

        1.2出现差错的情况

        下图中,B 接收 M1 时检测出了差错,就丢弃 M1,其他什么也不做,也就是说,B 并不会通知 A 收到有差错的分组。此外,还有一种可能是 M1 在传输过程中丢失了,此时 B 并没有收到数据。所以在这两种情况下,B 都不会也不应该发送任何信息。//这就是为什么可靠传输协议不应该由接收方来控制的原因

        那么,可靠传输协议是怎么设计的呢?

        A 只要超过了一段时间仍然没有收到确认,就认为刚才发送的分组丢失了,因而重传前面发送过的分组。这就叫作超时重传。要实现超时重传,就要在每发送完一个分组时设置一个超时计时器。如果在超时计时器到期之前收到了对方的确认,就撤销已设置的超时计时器。

        这里应注意以下三点:

  • 第一,A 在发送完一个分组后,必须暂时保留已发送的分组的副本(在发生超时重传时使用)。只有在收到相应的确认后才能清除暂时保留的分组副本。//保留副本
  • 第二,分组和确认分组都必须进行编号。这样才能明确是哪一个发送出去的分组收到了确认,而哪一个分组还没有收到确认。//消息ID
  • 第三,超时计时器设置的重传时间应当比数据在分组传输的平均往返时间更长一些。这里需要注意的是,重传时间不能设定得很长,否则通信的效率就会很低。重传时间也不能设定得太短,否则就会产生不必要的重传,浪费网络资源。//重传时间

        1.3确认丢失和确认迟到的情况

        如果 B 所发送的对 M1 的确认丢失了。A 在设定的超时重传时间内没有收到确认,并无法知道是自己发送的分组出错、丢失,或者是 B 发送的确认丢失了。因此 A 在超时计时器到期后就要重传 M1。现在应注意 B 的动作。假定 B又收到了重传的分组 M。这时应采取两个行动。//确认丢失

        第一,丢弃这个重复的分组 M1,不向上层重复交付。

        第二,向 A 发送确认。不能认为已经发送过确认就不再发送,因为 A 之所以重传 M1 就表示 A 没有收到对 M1 的确认。

        还有就是传输过程中没有出现差错,但 B 对分组 M1 的确认迟到了。A 会收到重复的确认。对重复的确认的处理很简单:收下后就丢弃,但什么也不做。B 仍然会收到重复的 M1,并且同样要丢弃重复的 M1,并重传确认分组。//确认迟到

        使用上述的确认和重传机制,我们就可以在不可靠的传输网络上实现可靠的通信。像上述的这种可靠传输协议常称为自动重传请求 ARQ (Automatic Repeat reQuest)。意思是重传的请求是自动进行的,接收方不需要请求发送方重传某个出错的分组。

        停止等待协议中的信道利用率问题

        停止等待协议的优点是简单,但缺点是信道利用率太低。如下图所示,当往返时间 RTT 远大于分组发送时间 T_{D} 时,信道的利用率就会非常低。

        如果还考虑出现差错后的分组重传,那么出现重传时,对传送有用的数据信息来说,信道的利用率就还要降低。

        为了提高传输效率,发送方可以不使用低效率的停止等待协议,而是采用流水线传输,如下图所示:

        流水线传输就是发送方可连续发送多个分组,不必每发完一个分组就停顿下来等待对方的确认。这样可使信道上一直有数据在不间断地传送。显然,这种传输方式可以获得很高的信道利用率。//这就是连续 ARQ 协议和滑动窗口协议

(2)连续ARQ协议

        连续 ARQ 协议规定,发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置。在下图中,发送方收到了对第 1 个分组的确认,于是把发送窗口向前移动一个分组的位置。如果原来已经发送了前 5 个分组,那么现在就可以发送窗口内的第 6 个分组了。//连续ARQ协议的工作原理

        接收方一般都是采用累积确认的方式。这就是说,接收方不必对收到的分组逐个发送确认,而是在收到几个分组后,对按序到达的最后一个分组发送确认,这就表示,到这个分组为止的所有分组都已正确收到了。

        累积确认有优点也有缺点。优点是容易实现,即使确认丢失也不必重传;但缺点是不能向发送方及时反映接收方已经正确收到所有分组的信息。

        例如,如果发送方发送了前 5 个分组,而中间的第 3 个分组丢失了。这时接收方只能对前两个分组发出确认。发送方无法知道后面三个分组的下落,而只好把后面的三个分组都再重传一次。这就叫作 Go-back-N (回退N)表示需要再退回来重传已发送过的 N 个分组。可见当通信线路质量不好时,连续 ARQ 协议会带来负面的影响。

3、TCP 报文段的首部格式

        TCP报文段首部的前 20 个字节是固定的,后面有 4n 字节是根据需要而增加的选项(n 是整数)。因此 TCP 首部的最小长度是 20 字节。

        首部固定部分各字段的意义如下:

        源端口和目的端口各占 2 个字节,分别写入源端口号和目的端口号。和 UDP 的分用相似,TCP 的分用功能也是通过端口实现的。

        序号:占 4 字节。序号范围是 [0,2^{32}-1],共 2^{23}(即4 294 967 296)个序号。序号增加到 2^{32}-1 后,下一个序号就又回到 0。也就是说,序号使用 mod 2^{23} 运算。这个序号干嘛用呢?我们知道 TCP 是面向字节流的。传送的字节流中的每一个字节都需要按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值则指的是本报文段所发送的数据的第一个字节的序号。例如,一报文段的序号字段值是 301,而携带的数据共有100 字节。这就表明,本报文段的数据的第一个字节的序号是 301,最后一个字节的序号是 400。显然,下一个报文段(如果还有的话)的数据序号应当从 401 开始,即下一个报文段的序号字段值应为 401。这个字段的名称也叫作 “报文段序号”

        确认号:占 4 字节,是期望收到对方下一个报文段的第一个数据字节的序号。例如,B 正确收到了 A 发送过来的一个报文段,其序号字段值是 501,而数据长度是 200 字节(序号501~700),这表明 B 正确收到了 A 发送的到序号 700 为止的数据。因此,B 期望收到 A 的下一个数据序号是 701,于是 B 在发送给 A 的确认报文段中把确认号置为 701。请注意,现在的确认号不是 501,也不是 700,而是 701。

若确认号 = N,则表明,到序号 N-1 为止的所有数据都已正确收到。

        数据偏移:占 4 位,它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。这个字段实际上是指出 TCP 报文段的首部长度。由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的。

        保留:占 6 位,保留为今后使用,但目前应置为 0。

        下面有 6 个控制位,用来说明本报文段的性质,它们的意义如下:

        紧急URG(URGent):当 URG = 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据),而不要按原来的排队顺序传送。于是发送方 TCP 就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。这时要与首部中紧急指针(Urgent Pointer)字段配合使用。

        确认ACK(ACKnowledgment):仅当 ACK = 1 时确认号字段才有效。当 ACK = 0 时,确认号无效。TCP规定,在连接建立后所有传送的报文段都必须把 ACK 置为 1。

        推送PSH(PuSH):当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,TCP 就可以使用推送(push)操作。这时,发送方 TCP 把 PSH 置 1,并立即创建一个报文段发送出去。接收方 TCP 收到 PSH = 1 的报文段,就尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付

        复位RST(ReSeT):当 RST = 1 时,表明 TCP 连接中出现严重差错(如主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。将 RST 置为 1 还用来拒绝一个非法的报文段或拒绝打开一个连接。RST 也可称为重建位或重置位。

        同步SYN(SYNchronization):在连接建立时用来同步序号。当 SYN = 1 而 ACK = 0 时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使 SYN = 1 和 ACK = 1。因此,SYN 置为 1 就表示这是一个连接请求或连接接受报文。

        终止FIN(FINish):用来释放一个连接。当 FIN = 1 时,表明此报文段的发送方的数据已发送完毕,并要求释放运输连接。

        窗口:占 2 字节。窗口值是 [0,2^{16}-1] 之间的整数。窗口指的是发送本报文段的一方的接收窗口(而不是自己的发送窗口)。窗口值告诉对方,从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量(以字节为单位)。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。总之,窗口值作为接收方让发送方设置其发送窗口的依据。

        例如,发送了一个报文段,其确认号是 701,窗口字段是 1000。这就是告诉对方:“从 701 号算起,我(即发送此报文段的一方)的接收缓存空间还可接收 1000 个字节数据(字节序号是 701~1700),你在给我发送数据时,必须考虑到我的接收缓存容量”。

        总之,应当记住:

        窗口字段明确指出了现在允许对方发送的数据量,窗口值经常在动态变化着。

        检验和:占 2 字节。检验和字段检验的范围包括首部和数据这两部分。和 UDP 用户数据报一样,在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部。伪首部的格式与 UDP 用户数据报的伪首部一样。但应把伪首部第 4 个字段中的 17 改为 6(TCP 的协议号是 6),把第 5 字段中的 UDP 长度改为 TCP 长度。接收方收到此报文段后,仍要加上这个伪首部来计算检验和。若使用 IPv6,则相应的伪首部也要改变。

        紧急指针:占 2 字节。紧急指针仅在 URG = 1 时才有意义,它指出本报文段中的紧急数据的字节数。因此,紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据都处理完时,TCP 就告诉应用程序恢复到正常操作。值得注意的是,即使窗口为零时也可发送紧急数据。

        选项:长度可变,最长可达 40 字节。当没有使用“选项”时,TCP 的首部长度是 20 字节。

        填充字段:该字段仅仅是为了使整个 TCP 首部长度是 4 字节的整数倍。

(1)填充字段选项的说明

        TCP 最初只规定了一种选项,即最大报文段长度 MSS(Maximum Segment Size) [RFC6691]。MSS 是每一个 TCP 报文段中的数据字段的最大长度。数据字段加上 TCP 首部才等于整个的 TCP 报文段。所以 MSS 并不是整个 TCP 报文段的最大长度,而是 TCP 报文段长度减去 TCP 首部长度。

        ​​​​​​​为什么要规定一个最大报文段长度 MSS 呢?

        这并不是考虑接收方的接收缓存可能放不下 TCP 报文段中的数据。实际上,MSS 与接收窗口值没有关系,规定最大报文段长度是为了提高网络传输效率。一般情况下,只要在 IP 层传输时不需要再分片,MSS 就应尽可能的大一些。由于 IP 数据报所经历的路径是动态变化的,因此在某条路径上确定的不需要分片的 MSS,如果改走另一条路径就可能需要进行分片。因此最佳的 MSS 实际上是很难确定的。若主机未填写这一项,则 MSS 的默认值是 536 字节(这个数值来自 576 字节的 IP 数据报总长度减去 TCP 和 IP 的固定首部)。因此,所有互联网上的主机都应能接受的报文段长度是 536 + 20(固定首部长度)= 556 字节

        后来,填充字段又陆续增加了几个选项,如窗口扩大选项、时间戳选项、选择确认(SACK)选项等

        窗口扩大选项有什么作用呢?

        窗口扩大选项是为了扩大窗口。我们知道,TCP 首部中窗口字段长度是 16 位,因此最大的窗口大小为 64 KB。虽然这对早期的网络是足够用的,但对于包含卫星信道的网络,其传播时延和带宽都很大,要获得高吞吐率需要更大的窗口大小。

        窗口扩大选项占 3 字节,其中有一个字节表示移位值 S。新的窗口值等于 TCP 首部中的窗口位数从 16 增大到 (16 + S)。移位值允许使用的最大值是 14,相当于窗口最大值增大到2^{(16+14)}-1=2^{30}-1

        窗口扩大选项可以在双方初始建立 TCP 连接时进行协商。如果连接的某一端实现了窗口扩大,当它不再需要扩大其窗口时,可发送 S=0 的选项,使窗口大小回到16。

        时间戳选项有什么用呢?

        时间戳选项占 10 字节,其中最主要的字段是时间戳值字段(4字节)和时间戳回送回答字段(4字节)。

        时间截选项有以下两个功能:

        第一,用来计算往返时间 RTT。发送方在发送报文段时把当前时钟的时间值放入时间戳字段,接收方在确认该报文段时把时间戳字段值复制到时间戳回送回答字段。因此,发送方在收到确认报文后,可以准确地计算出 RTT。//存储发送时间和确认时间

        第二,用于处理 TCP 序号超过 2^{32} 的情况,这又称为防止序号绕回 PAWS (ProtectAgainst Wrapped Sequence numbers)。我们知道,TCP 报文段的序号只有 32 位,而每增加 2^{32} 个序号就会重复使用原来用过的序号。当使用高速网络时,在一次 TCP 连接的数据传送中序号很可能会被重复使用。例如,当使用 1.5 Mbit/s 的速率发送报文段时,序号重复要 6 小时以上。但若用 2.5 Gbit/s 的速率发送报文段,则不到 14 秒序号就会重复。为了使接收方能够把新的报文段和迟到很久的报文段区分开,可以在报文段中加上这种时间戳。

        至此,全文结束。

相关文章:

  • easyExcel - 动态复杂表头的编写
  • leetcode热题HOT146. LRU 缓存
  • 【简单讲解下Kotlin】
  • 蓝桥杯 - 受伤的皇后
  • redis的三大模式的演化及集群模式思考和总结
  • Git汇总
  • 【开源书籍】深入讲解内核网络、Kubernetes、ServiceMesh、容器等云原生相关技术。
  • JavaIO输入输出
  • 企业如何设计和实施有效的网络安全演练?
  • 大话设计模式——六大基本设计原则(SOLID原则)
  • 【C语言】扫雷小游戏
  • 路由Vue-Router使用
  • windbg托管内存泄漏排查
  • 魔众 文库配置异步转换
  • 网格矢量如何计算莫兰指数
  • SpringBoot学习之Kibana下载安装和启动(Mac版)(三十二)
  • Mac下Docker Desktop starting的解决方法
  • 电商系列之风控安全
  • C++--友元
  • 蓝桥杯 经验技巧篇
  • https://app.hackthebox.com/machines/Inject
  • Spring —— Spring简单的读取和存储对象 Ⅱ
  • 渗透测试之冰蝎实战
  • Mybatis、TKMybatis对比
  • Microsoft Office 2019(2022年10月批量许可版)图文教程
  • 《谷粒商城基础篇》分布式基础环境搭建
  • 哈希表题目:砖墙
  • Vue 3.0 选项 生命周期钩子
  • 【车载嵌入式开发】AutoSar架构入门介绍篇
  • 【计算机视觉 | 目标检测】DETR风格的目标检测框架解读