协议簇:TCP 解析: Sequence Number

简介

序列号(Sequence Number) 是 TCP 协议中非常重要的一个概念,以至于不得不专门来学习一下。这篇文章我们就来解开他的面纱.

在 TCP 的设计中,通过TCP协议发送的每个字节都对应于一个序列号. 由于每个字节都有自己的序列号,那么每个字节都可以被对方确认接收.

但是由于 TCP 使用累计确认机制,因此不需要对每个接收到的字节都发送对应的ACK,而是采用确认最后接收到的自己的序列号的方式来进行确认接收的. 举个例子,对于序列号 X, 它意味着 X 之前的所有字节已经被对方接收到(不包含 X 本身)。

序列号这个机制使得 TCP 可以检测到重复的数据包.

本篇文章中将会使用都很多我们在基本部分引入的专业术语,请参考 协议簇:TCP 解析: 基础

系列文章

协议簇:TCP 解析:基础
协议簇:TCP 解析:建立连接
协议簇:TCP 解析:连接断开
协议簇:TCP 解析:Sequence Number
协议簇:TCP 解析:数据传输

Sequence Number

正如我们所知道的,Sequence Number 字段在 TCP 头部占用 32bit 的长度。这也意味着 Sequence Number 是有限的,它的合法值是 0 - 2**32 -1. 因此对于通信双方,在发送 SEQ 时,总是需要将该值与 2 ** 32 取模.

TCP 任何一方在接收到对方发送的数据包之后,都需要对 Sequence Number 进行检查。 最通常的检查包含以下几条:

  1. 接收到的 Sequence Number 对应于那些我们已经发送还未收到 ACK 的 Sequence Number
  2. 一个TCP数据段所包含的所有字节都被当前 Sequence Number 覆盖(比如,我们可以将该段从重传队列中移除)
  3. 接收到的 Sequence Number 是我们正在等待接收的(比如,确保该 Sequence Number 于我们的接收窗口有重叠部分).
概念引入
  1. SND.UNA - 最早发送且没有收到ACK的 Sequence Number
                        [oldest unacknowledged sequence number]

  2. SND.NXT - 下一个被发送的数据的 Seuqnce Number
                        [next sequence number to be sent]

  3. SEG.ACK - 接收到的 TCP 段的 ACK,其中包含了对方期待下一个段的 Sequence Number
                        [acknowledgment from the receiving TCP (next sequence
    number expected by the receiving TCP)]

  4. SEG.SEQ - 一个 TCP 段的第一个字节的 Sequence Number
                        [first sequence number of a segment]

  5. SEG.LEN - 一个 TCP 段中包含的字节的数量
                        [the number of octets occupied by the data in the segment
    (counting SYN and FIN)]

  6. SEG.SEQ+SEG.LEN-1 - 一个 TCP 段的最后一个字节的 Sequence Number
                        [last sequence number of a segment]

  7. RCV.NXT - 下一个期待接收到的段的第一个字节的 Sequence Number. 同时,这个值也代表了接收方的接收窗口的下限.
                       [next sequence number expected on an incoming segments, and is the left or lower edge of the receive window]

  8. RCV.NXT+RCV.WND-1 - 下一个期待接收到的段的最后一个字节的 Sequence Number. 同时,这个值也代表了接收方的接收窗口的上限
                      [last sequence number expected on an incoming segment, and is the right or upper edge of the receive window]

对于数据发送方

在发送了 TCP 数据之后,正常情况下,我们都会收到相应的 ACK.

接收到的 ACK 需要满足条件: SND.UNA < SEG.ACK =< SND.NEXT

当一个处于重传队列的段的SEQ + 它的长度的和小于 ACK 的值,那么这个段已经被对方成功接收,可以从重传队列中移除。

对于数据接收方

接收到的段中包含的 SEQ 需要满足以下条件:
RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND (确保接收到的数据的第一个字节的 SEQ 处于接收窗口中)
OR
RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND (确保接收到的数据的最后一个字节的 SEQ 处于接收窗口中)

满足上述条件中任何一个条件,便可以判断当前接受到的数据部分处于接收窗口.

实际情况中,我们还需要考虑接收窗口为 0 和 空 TCP 段的情况. 那么就需要考虑以下四种情况:

Seg LenRcv WndTest
00SEG.SEQ = RCV.NXT
0>0RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND
>00not acceptable
>0>0RCV.NXT =< SEG.SEQ < RCV.NXT + RCV.WND
OR
RCV.NXT =< SEG.SEQ+SEG.LEN-1<RCV.NXT+RCV.WND

注意,当接收窗口为 0 之后,除了ACK之外,无法接收任何其他 TCP 段. (对于上表第三条)

Initial Sequence Number Selection

TCP 协议并不限制在 TCP 的实现中重复使用同一个连接. 一个连接仅仅由一对 socket 标识. (新的连接被成为前一个连接的“化身”[incarnation]) 但是存在一个问题: 如何判断一个TCP段来自前一个连接还是前一个连接的化身? 当一个连接被快速的打开关闭或者一个连接由于内存不足而断掉,恢复后又重新建立的情况下,会尤其明显.

在上述问题中,很有可能两个连接使用相同的序列号发送数据。这种情况下,我们无法区分这个数据包的来源. 因此,对于 TCP 而言,选择一个合适的 Sequence Number 非常重要.

当我们尝试建立一个连接时,我们需要在SYN中附上我们选择的 Sequence Number,也就是 Initial Sequence Number,简称 ISN. ISN 的生成方法如下:

ISN 生成器以当前机器时钟为基础,粗略地每4微妙增加ISN的最低有效位.
这个生成器生成的序列会以 4.55 小时为周期重复,但是设计者认为没有TCP段可以在网络上存活超过这个时间,因此他们认为这样选择 ISN 是非常合理的.

对于每个TCP连接,都包含两个 Sequence Number,分别由 TCP 双方独立生成. 在一个 TCP 连接建立之前,双方应该回想通告自己的 Sequence Number (协议中称之为“synchronize”). 互相通告自己的 Sequence Number 需要每方均发送自己的 ISN 并收到对方发送的 ACK, 以确保对方收到了己方的 ISN.
大体的流程如下:
在这里插入图片描述
又由于 TCP 连接是全双工的,在接收的同时可以发送数据,那么2,3步可以合并为一步。最后, 就有了现在的 “三次握手" 了.

END!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499678.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

协议簇:TCP 解析:TCP 数据传输

简介 前面&#xff0c;我们分别介绍了 TCP 基础知识以及连接的建立和关闭&#xff0c;以及最重要的 Sequence Number 的概念. 本篇文章&#xff0c;我们来介绍一下 TCP 如何传输数据. 系列文章 协议簇&#xff1a;TCP 解析&#xff1a;基础 协议簇&#xff1a;TCP 解析&…

CodeTank iOS App Technical Support

CodeTank iOS App Technical Support For All Email: z253951598outlook.com TEL: 86-17782749061 App Screen Shoots

CentOS 7 防火墙命令

查看防火墙状态 systemctl status firewalld如果已经开启&#xff0c;状态为 active 如果未开启&#xff0c;状态为 inactive 开启防火墙 systemctl start firewalld关闭防火墙 systemctl stop firewalld查看当前防火墙的配置 firewall-cmd --list-all这里&#xff0c;我…

Go Concurrency Patterns: Context

Go Concurrency Patterns: Context 原文地址&#xff1a;https://blog.golang.org/context Introduction 在 Go 语言实现的服务器上&#xff0c;我们总是使用 goroutine 来处理与客户端建立的连接&#xff0c; 给每个连接分配一个独立的 goroutine. 在请求的 handler 中也通常…

Go Concurrency Patterns: Timing out, moving on

原文地址&#xff1a;https://blog.golang.org/concurrency-timeouts 并发变成有它自己的风格. 一个非常好的例子就是 timeout. 虽然 go 的 channel 没有直接支持 timeout 机制&#xff0c;但是要实现它非常容易. 比如说&#xff0c;我们想从一个 channel ch 中接收数据&#…

Go Concurrency Patterns: Pipelines and cancellation

原文地址&#xff1a; https://blog.golang.org/pipelines 简介 Go 语言提供的并发原语使得可以很方便的构建数据流 pipeline&#xff0c;使用这样的 pipeline 可以高效的利用 I/O 和多 cpu 的优势. 这篇文章我们将展示如何构建并使用 pipeline. 什么是 pipeline ? 在 go 语…

QTcpSocket connectToHost 建立连接速度慢问题

问题场景 在使用 QT 开发一个客户端 App 的时候&#xff0c;我们通过 QTcpSocket 与后台服务器进程通信。 后台程序使用其他语言编写。 问题&#xff1a; 在客户端启用之后尝试建立与后台程序的 TCP 连接的时候&#xff0c;发现连接速度非常慢&#xff08;肉眼可见的慢&#x…

WinSock I/O 模型 -- Select 模型

简介 Select 模型是 WinSock 中最常见的 I/O 模型&#xff0c;这篇文章我们就来看看如何使用 Select api 来实现一个简单的 TCP 服务器. API 基础 Select 模型依赖 WinSock API Select 来检查当前 Socket 是否可写或者可读。 使用这个 API 的优点是我们不需要使用阻塞的 So…

WinSock I/O 模型 -- WSAEventSelect 模型

简介 WSAEventSelect 模型也是 WinSock 中最常见的异步 I/O 模型。 这篇文章我们就来看看如何使用 WSAEventSelect api 来实现一个简单的 TCP 服务器. API 基础 WSAEventSelect WSAEventSelect 用来把一个 SOCKET 对象和一个 WSAEVENT 对象关联起来。 lNetworkEvents 表示…

WinSock I/O 模型 -- WSAAsyncSelect 模型

简介 WSAAsyncSelect 模型也是 WinSock 中常见的异步 I/O 模型。 使用这个模型&#xff0c;网络应用程序通过接收以 Windows 消息为基础的网络事件通知来处理网络请求。 这篇文章我们就来看看如何使用 WSAAsyncSelect api 来实现一个简单的 TCP 服务器. API 基础 要使用 W…

WinSock I/O 模型 -- OVERLAPPED I/O 模型

简介 OVERLAPPED I/O 模型也是 WinSock 中常见的异步 I/O 模型&#xff0c;相比于我们之前提到的 Select 模型&#xff0c;WSAAsyncSelect 模型 和 WSAEventSelect 模型有更好的性能. 为了方便描述&#xff0c;下文我们将称 Overlapped I/O 模型为 “重叠模型”. 重叠模型的…

WinSock I/O 模型 -- IOCP 模型

前言 IOCP 全称 Input/Ouput Completion Ports&#xff0c;中文中翻译一般为“完成端口”&#xff0c;本文中我们使用 IOCP 简写. IOCP 模型是迄今为止最为复杂的一种 I/O 模型&#xff0c;但是同时通过使用 IOCP 我们往往可以达到最佳的系统性能. 当你的网络应用程序需要管理…

GTank iOS App Technical Support

GTank iOS App Technical Support For All Email: z253951598outlook.com TEL: 86-17782749061 App Screen Shoots ​​

证书体系: CSR 解析

原文同时发布于本人个人博客&#xff1a; https//kutank.com/blog/cert-csr/ 简介 CSR 全称 “证书签名请求”(Certificate Signing Request). 本文我们将来详细的学习 CSR 的知识&#xff0c;重点集中在 CSR 所包含的信息&#xff0c;及其意义。 CSR 的作用: CSR 通常由想要获…

胡思乱想

学了一段时间的OGRE,才知道什么才称得上"建筑师",而我们只不过是"砌墙匠" 他们在算法算法,我们在Coding Coding,怎样才能有所改观呢~~~想当初还不如选数学专业再来学计算机可能好些, 但是既然选择了先学计算机这条路,那就先Coding,边Coding边提高数学能力…

关于数据库备份的问题

首先我们来看数据库帮助上面的sql语句&#xff1a; BACKUP DATABASE Northwind TO DISK c:/Northwind.bakRESTORE FILELISTONLY FROM DISK c:/Northwind.bakRESTORE DATABASE TestDB FROM DISK c:/Northwind.bak WITH MOVE Northwind TO c:/test/testdb.mdf, MOVE N…

关于函数指针调用C++非静态成员

当在类里面定义函数指针&#xff0c;而函数指针会指向类里面的成员的时候&#xff0c;这个时候成员需要定义为静态成员。实例代码如下&#xff1a; //.h#define SCMD_REGISTER 0class CCallFuctionList{public:CCallFuctionList();virtual ~CCallFuctionList(void);typedef…

重构心得

重构入手&#xff1a; 1. 找到牵连最广模块。 2. 找到上述模块中需要重构的相关的子类。 3. 原来代码不删除&#xff0c;保证编译运行。 4. 陆续重构其他模块 再列出我觉得可以借鉴的重构方法。【摘自代码大全】 1.保存初始代码。用你的版本控制系统保存一个初始版本&#x…

跨模块中的分配内存问题

现在有dll模块A,dll模块B以及静态库C, C中有个全局Create()函数负责创建对象M,当第二次调用Create()的时候会增加引用计数&#xff0c;并返回原来创建的对象M。Relase()会减少引用计数。当引用计数为0时&#xff0c;销毁对象M。现在在模块A中创建的初始化对象M&#xff0c;模块…

CListControl的OnMouseMove和OnNcHitTest

实际案例如下&#xff1a; 将CListCtrl做成菜单样式。需要处理当鼠标移到ClistCtrl上的事件。 处理逻辑这样&#xff1a;当鼠标移动到CListCtrl区域时候&#xff0c;将CListCtrl上所有ITem置为非选中状态&#xff0c;然后调用HitTest得到行数再将所选行置为选中状态。当鼠标移…