计算机网络:运输层 - TCP首部格式 & 连接的创建与释放


TCP首部格式

TCP的首部如下:

在这里插入图片描述

首部的前20 byte是固定的,后面的选项字段可变。

源端口 目的端口

源端口目的端口各占2 byte,即填入通信的两个进程使用的端口号。


序号

4 byte,范围是 [ 0 , 2 32 − 1 ] {\red{[0, 2^{32} - 1]}} [0,2321]TCP是面向字节流的,在TCP中传输的每一个字节都要按顺序进行编号。整个传输过程中,第一个字节的值是任意的,由发送方随机设定,后续所有字节都由第一个字节的编号以及偏移量得出。比如整个TCP连接中,第一个字节编号为x,那么第201个字节的编号就是x + 201

如果某个字节在编号时,超出了 2 32 − 1 2^{32} - 1 2321 ,此时从0开始重新计数。


确认号

4 byte,含义是:期望收到对方下一个报文段的第一个字节的序号

例如,主机B收到了来自A的编号为501的数据报,数据报长度为200。这说明主机B收到了编号为501 - 700字节的数据。那么主机B接下来就期望收到701开始的数据,此时确认号就设为701

若确认号为 n,说明 n - 1 及之前的所有数据都已经收到了


数据偏移

4 bit,其含义为:报文起始处数据起始处的距离,简单理解就是整个首部的长度

由于TCP带有填充字段,所以长度是不确定的,需要该字段来指明长度。另外的,由于只占该字段只占4 bit,能表示的范围是 [ 0 , 2 4 − 1 ] {\red{[0, 2^{4} - 1]}} [0,241],也就是[0, 15],而数据偏移字段以4 byte为单位。所以整个首部的长度最长为60 byte,进而说明选项字段的长度不超过40 byte


保留

6 bit,目前没有用,使用时设为全0


控制位

接着就是连续的留个控制位

紧急 URG:当URG = 1,表明紧急指针字段有效,告诉系统此报文有紧急数据,需要尽快传送,此时该报文就无需排队,直接插入到队列的首部立马发送出去。

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

推送 PSH:发送该报文后,如果希望尽快收到对方的回应,就可以PSH = 1。接受方收到该报文后,会立刻把该报文提交给应用进程,而不是等到接收缓存满了才提交。

复位 RST:当RST = 1,表示TCP连接出现重大差错,必须释放连接。也可以用来拒绝一个连接或报文段。

同步 SYN:用于建立连接

  • SYN = 1并且ACK = 0,表明这是一个连接请求报文,(ACK = 0的情况,一般来说整个TCP连接只有此处ACK = 0)
  • SYN = 1并且ACK = 1,表明这是一个连接同意报文

终止 FIN:用于释放一个连接,当FIN = 1,表明这是一个释放连接的报文


窗口

2 byte,用于指明自己的接收窗口,对方收到该报文后,读取窗口字段,就知道自己接下来可以发送多少数据了。


检验和

2 byte,检验范围包括首部数据两部分,与UDP一样,在计算检验和时,要加上伪首部

如图:

在这里插入图片描述

只有计算检验和时才会存在伪首部,实际上其不存在,TCP 数据报中只有首部数据


紧急指针

2 byte,仅在URG = 1时才有效。当URG = 1,说明这是一个紧急的报文,此时要立刻发出去,整个数据报会插队到其他数据报的前面。那么计算机怎么知道这个紧急报文的长度是多少?

此时就需要紧急指针字段,其指明了本报文中紧急数据的字节数,当把所有紧急数据处理完后,就要恢复正常状态,把之前的数据发送出去。而什么时候紧急数据发送完,就是依靠紧急指针字段指明的紧急数据的字节数。


讲解完报文的格式后,我们来讲解TCP连接的创建与释放。后续会用到一些标识符,接下来我解释一下每个标识符对应数据报首部的哪一个字段:

  • seq:对应首部中的序号字段,指明希望收到的下一个数据的序号是什么
  • ack:对应首部中的确认号字段,表明xxx之前的所有数据都已经收到了
  • ACK:对应首部中的确认位字段,表明确认号有效
  • SYN:对应首部中的同步位字段,用于创建TCP连接
  • FIN:对应首部中的终止位字段,用于终止TCP连接

TCP连接创建 - 三次握手

假设现有一台客户主机A,一台服务器主机B,现在A申请向B发起TCP连接

处于创建连接的过程中,SYN就起作用了,如图:

在这里插入图片描述

首先令SYN = 1,表明当前正在创建连接,创建连接的报文分两种情况:

  • SYN = 1并且ACK = 0,表明这是一个连接请求报文,(ACK = 0的第一种情况)
  • SYN = 1并且ACK = 1,表明这是一个连接同意报文

当前A正在发起连接的请求,所以此时ACK = 0,注意:后续只要不标明的位,都是0

而发送数据是要对每个字节进行编号的,第一个字节的编号由主机随机生成,此时seq = x表明:第一个字节的编号为x

A发起请求后,此时B就要同意这个连接:

在这里插入图片描述

同意连接是SYN = 1ACK = 1,表明当前报文用于同意一个连接。此时主机B也要生成第一个字节的编码,也就是seq = y

B在回应时,还有一个字段ack = x + 1ack表示:我希望收到的下一个数据的编号。

比如说某一次报文发送时,第一个字节的编号为666,总数据长度为200 byte,那么接收方就收到了[666, 865]的所有数据,此时回应报文为ack = 866表明下一个数据的编号为866

那么目前来说刚刚TCP请求报文的编号为seq = x,现在我回应ack = x + 1,是不是可以理解为:整个TCP请求报文只携带一个字节的数据呢?

TPC规定:SYN = 1的报文不允许携带数据,但是消耗掉一个seq

其实SYN = 1的报文不携带数据部分,但是TCP强制规定了其要消耗掉一个seq,因此刚刚序号x视为被消耗了,下一个字节的序号为x + 1

A收到B的确认后,此时A也要再给B做一次确认:

在这里插入图片描述

这个确认,是对第二个报文的确认,此时SYN = 0,因为其既不是连接请求,也不是连接同意ACK = 1表明ack字段有效。seq = x + 1,因为第一个报文seq = x,并且SYN = 1要消耗掉一个需要,此时就用下一个序号x + 1

ack = y + 1是因为,刚刚B发送的报文seq = y,而SYN = 1要消耗掉一个序号,此时希望收到的下一个序号为y + 1

接下来考虑一个问题:为什么需要三次报文交换才能建立连接?明明A发送一个请求,B发送一个同意,就表明双方都准备建立连接了,为什么不直接开始传输数据,而是还要第三次确认?

这是因为在B发送第二个同意报文后,A可能还没准备好接收数据。比如说B发送的同意报文丢失了,此时A还在等待B的同意,而B以为A已经可以发送数据了。结果B发送了一段数据后,A根本不接收,因为A在等B的同意。此时就是A没有准备好。

因此A要发送第三个报文,来表明自己已经准备好了,对面可以开始发送数据了。

另外的,第三个报文是可以携带数据的,此时A发送第三个报文时,表明连接建立完毕了,于是A就顺带可以把一部分数据先通过该报文传输过去!

对于FIN = 0SYN = 0ACK = 1的报文,可以携带数据,携带多少数据就消耗多少序号,如果不携带数据,就不消耗序号

现在连接已经创建完毕,就可以正常数据传输了!


TCP传输过程

很多地方都只讲了连接创建与释放的过程,反而没有说明传输的过程。其实这个过程也很重要,本博客再简单讲解一下传输的过程。

如图所示:

在这里插入图片描述

现在TCP连接建立时,第三个报文携带了100个数据(data用于说明这个报文携带了多少数据)。

随后A又紧接着发送了300个数据:

在这里插入图片描述

此时seq = x + 101,这是因为刚刚的第三个报文携带了100 byte的数据,其中第一个字节的编号为x + 1,说明我已经把[x + 1, x + 100]的数据发出去了,接下来的300字节,第一个编号就是x + 101了。

ack = y + 1,这是因为上一次收到B的报文是SYN = 1ACK = 1的连接同意报文,序号为y,消耗掉一个序号后变为y + 1,即下一个希望收到的编号为y + 1

随后B发送了一个长度为200 byte的报文:

在这里插入图片描述

此时seq = y + 1,这是因为上一次B发送的报文是seq = y,而SYN = 1消耗掉一个序号,这次第一个字节使用的序号为y + 1ack = x + 401表明[x, x + 400]的所有数据都收到了,下一个希望收到的序号是x + 401

随后A再发送一个100 byte的报文:

在这里插入图片描述

这时seq = x + 401,因为之前发送了[x, x + 400]的数据,下一个字节编号为x + 401ack = y + 201表明[y, y + 200]的数据都受到了。

以此类推,直到连接释放。


TCP连接释放 - 四次挥手

TCP连接传输数据完毕,此时就可以释放连接了。

TCP连接释放可以由任意一方发起,假设现在A发起释放连接:

在这里插入图片描述

首先要把FIN = 1,表明A发起了一个释放连接的请求。而seq = u,表明当前的报文编号为u,也说明之前A传输的最后一个字节编号为u - 1ack = v,表明A收到的来自B的最后一个字节是u

A发起释放连接的请求,只说明A要传送的数据已经完毕了,可以释放连接了。但是B可能还有没有传送完的数据

在这里插入图片描述

首先B发送一个ACK报文,表明自己已经收到了刚刚FIN = 1的报文。

TCP规定:FIN = 1的报文,就算不携带数据也要消耗一个序号

A发送的连接释放报文中,FIN = 1并且不携带数据,那么也要消耗掉一个序号。因此B希望收到的下一个序号是u + 1

如果B收到该报文,那么ack = u + 1,否则ack = u,这样发送方就可以根据下一个报文得知B有没有收到连接释放的请求包围了

随后B可以继续发送自己之前没发完的数据,这期间B发送的报文FIN = 0,表明B还有数据要发,没这么快终止连接。

剩下B发送的所有报文中ack = u + 1,因为刚刚A发送了一个FIN = 1的报文。

seq = v,表明自己现在发送的数据中,第一个字节序号为v

B传输完自己的所有数据后,在发送释放连接的同意报文:

在这里插入图片描述

FIN = 1表明这是一个连接释放的报文,在两个FIN = 1的报文中间,B还发了一些报文,导致序号一直增加,假设现在增加到了w,那么seq = w

B发送完最后一个FIN = 1的连接释放报文后,A最后发送一个确认报文:

在这里插入图片描述

这是因为B无法保证自己发出去的报文A一定可以接收到,如果B发送的FIN = 1的报文丢失了,此时B以为自己以为结束TCP连接,而A还在一直等待B发出FIN = 1的报文。所以要对这个FIN = 1的报文最后做一次确认。

当这四个报文传输完毕,A不能直接结束,而要等待2 MSL

在这里插入图片描述

MSL(Maximum Segment Lifetime,最大报文段生存时间):指的是一个 TCP 报文在网络中存活的最长时间。

这是因为A传送的最后一个确认报文也有可能丢失,B如过发现A没有回应,超时计时器结束就重传FIN = 1的报文。而这个报文一定可以在2 * MSL期间到达,所以如果A2MSL期间没有收到B的报文,说明最后一个报文B收到了,可以释放连接了。


  • 35
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盒马盒马

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值