- **💂 个人主页:**努力学习的少年
- 🤟 版权: 本文由【努力学习的少年】原创、在CSDN首发、需要转载请联系博主
- 💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦
一. Tcp报文段的结构
Tcp报文段是由报头字段和数据字段组成,数据段包含一块应用数据。
源端口号:表示发数据那个进程的端口号。
目的端口号:表示收数据那个进程的端口号。
校验和 :写入取人数据是否完整的数值
选项:扩展Tcp功能时使用,决定了Tcp报头的大小
紧急指针:当标志位URG为1时,则紧急指针生效,当紧急数据存在并给出指向紧急数据尾的指针时,TCP必须通知接受方的上层实体。
二. 首部长度
在Tcp报头字段中的选项可有可无,如果Tcp报头中没有选项的话,那么Tcp报头字段的大小为20个字节,但是如果Tcp报头字段中加入选项后,那么Tcp报头字段的大小就不止20个字节,所以**Tcp的报头字段的大小是不固定的**。为了**标识Tcp报头的大小**,Tcp就引入**首部长度**的概念。首部长度的大小是4个bit位,它最大时是1111,也就是15,但是首部长度的基本单位是4个字节,也就是说报头的最大的大小是15*4,也就是60个字节。
- 首部长度是标识Tcp报头的大小
- 首部长度的基本单位是4个字节
- 报头字段最大是60个字节,首部长度存放的是1111.
- 报头字段最小是20个字节,首部长度存放的是0101,也就是没有加入选项。
问题:Tcp中的报头和有效载荷是如何分离的?
当两台主机建立通信的时候,**会每次发送报文段(报头+有效载荷)的大小是固定的**,所以当一台主机收到一个报文段的时候,Tcp层面会根据报头字段中的首部大小确认报头的大小,然后读取根据这个大小读取出报头,报文段剩下的就是有效载荷。
三. 窗口大小
Tcp通信过程是会建立发送缓冲区和接受缓冲区的,当主机A和主机B建立好Tcp通信的时候,**主机A和主机B都会在Tcp协议层面建立好发送缓冲区和接受缓冲区**。发送缓冲区是将数据发送给对端主机的接收缓冲区上的。
** *窗口大小是用来进行流量控制的,它用来告诉对端主机自己的接收缓冲区剩余的大小。当两台主机建立通信的时候,通过三次握手互相交换各自窗口的大小,就能够互相知道对方主机的接收缓冲区的大小。同时,给对端发送报文字段的时候,也可以告诉对端主机自己的接收缓冲区接收缓冲区剩余的大小。*
举个例子:当主机B中的接收缓冲区只剩下1000字节大小的时候,那么主机B会将回应过去的Tcp协议中的窗口大小是1000,当主机A收到主机B的响应后,通过响应的窗口大小判断出主机B的接收缓冲区剩余的大小,因此下一次主机A给主机B发送数据的时候是不会超过1000个字节的数据,这样就可以防止主机B接收缓冲区满了之后出现丢包的情况。
四. 序列号和确认序号
1.序列号
在我们的**发送缓冲区中的每一个字节的数据都有一个编号,这个编号就是我们的序列号**。 Tcp把数据看成一个无结构但是有序的字节流,我们从TCP对序号的使用可以看出这一点,这是因为序号建立再传送的字节流上,而不是建立再传送的报文段的序列之上。**一个报文段的序号是该报文段首字节的字节流的编号**。假设一个报文段的大小是1000个字节**(报文段大小在建立同时新的时候双方就已经约定好了大小**), 则第一报文段的大小是1,第二个报文段的大小是1001,第三个报文段是2001,以此类推。每一个序列号被填入到相应TCP报文段报头的序列号字段中。
当接收方收到数据的时候,会根据序列号,按照顺序排列成一段,因此序列号可以解决数据在网络发送的过程中出现乱序的问题。
2.确认序号
TCP是全双工的,因此主机A在向主机B发送数据的同时,也会接收来自主机B的数据。从主机B到达的每个报文段中都有一个序列号用于从B流向A的数据。**主机A填充进报文段的确认序号是主机A期望从主机B中收到下一个字节的序列号**。**举个例子**: 假设主机A收到主机B的1~1000的所有字节,同时假设它要发送一个报文段给主机B,主机A等待主机B中1001即其以后的字节,那么主机A会在报文段的确认序号字段填充上1001.
再举一个例子:
假设**A收到**一个来自**主机B**的包含字节1~1000的**报文段**,以及另一个包含字节2001~3000的报文段。由于某种原因,主机A没有收到主机B发出来的包含字节1001~2000的报文段,主机A为了重组主机B的数据流,仍在等待字节1001(和其后的字节),因此,A**发送给B的下一个报文段中将在确认序号中填充1001**。 **在第二个例子中**,有个微秒的问题,当主机在收到第二个报文段(字节1001~2000)之前收到第三个报文段(字节2001~3000).因此,**第三个报文失序到达**,问题是:当主机在TCP连接的时候收到的失序报文段该怎么办?有趣的是,TCP并没有明确规定任何规则,而是把这个问题留给实现TCP编程人员去处理,他们有两个基本选择.
- 1.接收方立刻丢弃失序的报文段
- 2.接收方保留失序的报文段,并等待缺少字节以填充该间隔。
显然,后一种选择对网络带宽更加有效,也是实践中采用的方法。
3.序号和确认序号的一个学习案例
假设主机A与主机B建立好了TCP连接,然后主机A与主机B开始通信,假设**主机A和主机B的起始序列号分别是11和45**.假设每一个报文段为1.
(ps:Seq为序列号,ACK为确认序号)
![](https://img-blog.csdnimg.cn/503c17fe94b447c6a1856749e59d080d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Yqq5Yqb5a2m5Lmg55qE5bCR5bm0,size_20,color_FFFFFF,t_70,g_se,x_16)
如上图所示,第一个报文段是主机A发送给主机B的,其数据段中包含字符"A"的ASCII码,其序号字段是11,这如我们刚讲到的那样。另外,由于客户机还没有接收到来自服务器的任何数据,因此该报文段中的确认序号中填充的是45。
第二个字段是由主机B发送给主机A,它有两个目的:第一个目的是为主机B所收到的数据提供确认,因此主机B在确认序号中填充12,告诉主机A,它已经收到字节11及以前的所有字节,现在正等着字节12的出现。第二个目的是发送字符"B”,因此,在第二个报文段中的数据段填充的私字符" B " 的ASCII码值,并且将报文段的序列号填充为45。注意到对客户机到服务器的数据的确认被装载在一个程种主机B到主机A的数据的报文段中,这种确认被称之为捎带在主机B到主机A的数据报文段中。
第三个报文段是主机A发送给主机B的,它唯一的目的是确认已从主机B中收到数据。该报文段中的数据字段为空,该报文段中的确认序号填充为46,因为主机A收到了主机B字节流为12及以前的字节,它现在在等字节80的出现。即使没有报文段中没有数据,但报文段中一定需要填充某些序号。
五. 6比特标志位
1. 标志位的含义
- ACK:如果ACK为1是用于指示确认字段中的值是有效的,即该报文段包括一个对已被接收报文段的确认
- URG:如果URG为0,紧急指针无效,无需关注紧急指针,如果URG为1,那么紧急指针就有效.
- SYN:该比特位是请求对端开始建立连接。
- FIN:该比特位是要求与对端断开连接。
- PSH:该比特位设置时,指示对端立即将数据交给上层。
- RST:当一直没有收到对端的确认时,则会强制切断通信,然后重新建立通信。
2.建立通信的过程
两台主机开始建立通信的时候需要ACK和SYN来联系。下一篇文章将会详细地讨论TCP连接的建立过程。主机A与主机B连接建立的过程中:
- 第一个报文段是主机A给主机B发送一个SYN设置为1的报文段,表示向主机A向主机B发起连接请求。
- 第二个报文段是主机B给主机A的,该报文段将SYN和ACK都设置为1,它有两个目的:一个表示主机B收到主机A的报文段,另一个表示主机B向主机A发起连接请求。
- 第三个报文段是主机A给主机B的,该报文段将ACK都设置为1,表示的是主机A确认收到主机B连接请求。
**前两个报文段不承载" 有效载荷 ”,也就是不包含应用层数据,而第三个报文可以承载有效载荷**,由于在这两台主机之间发送了3个报文段,所以这种连接建立过程常被称之为三次握手。**建立过程中会确认好接下来双方发送的报文段的大小。**比如确认好的报文段为1000个字节,那么接下来双方每次发送的报文段都为1000个字节。
TCP不能保证百分之百连接的,因为:
在上面的连接过程中,如果第一个报文段丢失后,在一段时间内主机A没有收到第二个报文段,那么主机A就认为第一个报文丢失了,就会重发第一个报文段,直到主机A收到第二个报文为止。同样,如果第二个报文段丢失后,在一段时间内主机B没有收到第三个报头进行确认,那么主机B就会重发第二个报文段,直到主机B收到第三个报文为止。但是如果第三个报文段丢失后,主机A和主机B不知道,因为第三个报头没有响应报文段,如果主机B没有收到第三个报文段,则主机B是不会建立连接的,也就是说它没有建立好通信缓冲区(发送缓冲区+接收缓冲区)。但是主机A发送完第三个报文后会认为已经跟主机B建立好连接,就会建立好通信缓冲区。此时如果主机A再给主机B发送报文段的时候,当主机B收到报文段的时候,就知道对端已经建立好连接,但是自己没有建立好连接,就会发送一个RST为1的报文段给主机A,告诉它自己没有建立好连接,请断开连接,再重新建立连接。
3.断开连接
TCP断开连接的过程需要用FIN和ACK来联系的,具体断开细节下篇文章会将会讨论。
六. 写到最后
到此为止TCP报文段就讲解完了,同时也欢迎大家在评论区上同博主进行交流,如果有什么问题,我也可以给大家提供支持。
最后,如果觉得文章对你有帮助的话,请给博主关注,点赞,收藏,博主将会不断做出优质的文章给大家。
系列文章
【Linux网络(C++)】——网络套接字(TCP/UDP编程模型)多进程,多线程,线程池服务器开发(画图解析)
【linux多线程(四)】——线程池的详细解析(含代码)
3.【项目】----自主搭建个人博客
版权归原作者 努力学习的少年 所有, 如有侵权,请联系我们删除。