前言: 本节内容继续传输层的讲解, 本节讲解的是tcp协议。 tcp协议是我们日常中最常用的协议。就比如我们浏览网页,我们知道网页时http或者https协议。 其实http或者https底层就是用的tcp协议。tcp协议,全名又称为传输控制协议,Translation Control protocol。现在为话不多说, 开始我们的学习吧!
ps:关于讲解tcp, 仍旧采取和udp同样的策略。 先讨论tcp的报头和有效载荷如何分离, 然后讨论报头里面的内容, 最后是tcp的相关知识点。 本节内容是进入传输层tcp的第一节内容, 没有前置知识点, 友友们只要使用过tcp的socket相关接口就可以学习哦!
目录
为什么叫做TCP(传输控制协议)
TCP报头分离
十六位窗口大小
流量控制
确认应答机制
十六位窗口控件
32位序号和32位确认序号
捎带应答
超时重传
32位序号
32位确认序号
为什么要有两种序号
为什么叫做TCP(传输控制协议)
tcp协议在操作系统内部有一个叫做发送缓冲区,一个叫做接收缓冲区。然后平时我们在写代码的时候,我们自己在上层写的缓冲区,叫做用户缓冲区。
我们平时使用的write,rev,read,send这些,本质上不是发送函数,而是拷贝函数。是将用户级缓冲区里面的内容,拷贝到内存级缓中区里面。至于数据什么时候发送,发送多少,出错了怎么办,由TCP协议自主决定。 这个就是自主控制,又因为它在传输层是来传输的, 所以就是传输控制。
这个知识点,就和我们之前学习文件是一样的,我们之前使用write,等接口,本质上就是把数据拷贝到内核的文件缓冲区里面。至于这个数据什么时候刷,刷多少,出错了怎么办,是由内核决定的。所以,从今天来看,磁盘和网络没有区别,只是将磁盘设备换成了网卡,就可以完成数据的IO,文件是IO,网络也是IO。下面这张图, 就是整个的传输控制过程:
这里有个小的点就是关于全双工:tcp无论是客户端,还是服务端都能够接收和发送,这个过程,就叫做全双工。
TCP报头分离
下面是整个的TCP报文。
十六位源端口号和十六位目的端口号,就知道我们要把数据交给哪个主机。
标准报头是固定大小,固定20个字节。所以拿20个字节就是把标准报头全部拿到了。这个时候,就能拿到里面的一个字段:4位首部长度,标识报头的总长度是多少(标准 + 选项)。 四位首部长度长度最大范围是[0000, 1111], 也就是[0, 15]。 单位是4,也就是说, 四位首部长度的范围是[0, 60]。 所以, tcp报头最多是60字节, 标准占20, 所以选项最多就是40个。
如果我们不谈选项,这个四位首部长度x * 4 = 20 ==> x = 5;也就是说0101, 那么四位首部长度最少就是0101。 最多是1111。另外,这里这个四位首部长度, 我们可以叫他自描述字段。
所以, 如何分离报头和报文, 就是:固定长度 + 自描述字段。
十六位窗口大小
我们第一个要谈的报头信息是十六位窗口大小。
先说结论, 这个十六位窗口大小填写的是自己的接收缓冲区的大小。
为什么要有这个十六位窗口大小? 这个就涉及到了两个其他的知识点。 一个是‘流量控制’, 一个是‘确认应答’。下面我们来看一下这两个知识点:
流量控制
首先看一下流量控制
首先我们先看一下客户端和服务端的报文交互:
对于客户端和服务端来讲, 双方的任何通信, 都要有完整的报头, 就比如客户端发送一个你好,就要添加上完整的报头, 然后你好作为数据。 发送给服务端, 然后就写入了服务端的接收缓冲区。 服务端发送给客户端同样如此, 都是写入到客户端的接收缓冲区。
但是, 有一个问题,我们的客户端向服务端发送请求的时候, 如果客户端请求发送的很快,服务端请求拿的很慢, 或者根本就不拿。 那么是不是就总是有一刻服务端的接收缓冲区被打满?服务端的接收缓冲区一旦被打满, 客户端如果再向服务端发送数据, 那么这些数据就写不进去, 就一定会出现大面积丢包的情况。所以, 客户端就要有手段能够降低发送请求的速度或者干脆不发了, 这种手段, 就叫做流量控制!!!
确认应答机制
什么是确认应答,就比如我们在和朋友在微信上面现天我们对我们的用友说,吃饭了吗。我们的朋友如果看到了,就会说:吃了。我们看到"吃了“,我们就知道对方看到了我们的消息,这就是确认应答。
所以,确认应答机制, 就是:客户端向服务器发送任何请求、消息的时候,服务器都要向客户端进行响应。这样客户端就能保证,客户端到服务器方向的可靠性。相反,服务器向客户端发送的任何请求,客户端都响应,就能保证服务器到客户端方向的可靠性。
十六位窗口控件
客户端流量控制,发送的慢一点,依据是什么?对于发送方来说,发送的速度是由对方的接收缓冲区中剩余空间的大小来决定。问题是,我怎么知道对方的接收缓冲区中剩余的空间大小呢?别忘了,我们的tp是基于确认应答机制的,我们给服务端发送一个信息,对方就要返回给我们一个响应。对方给我们的响应里面又是包含完整的报头的! 报头里面又有一个16位窗口大小! 所以,这个16位窗口大小,填充的就是自身的接收缓冲区的剩余空间的大小!!!
所以, 下一个定义:16位窗口大小,填写的是自己的接收缓冲区中的大小!!
32位序号和32位确认序号
在正式讲解这个报头字段之前先讨论两个小知识点:捎带应答和超时重传。
捎带应答
什么是捎带应答,就是C或者S发了应答,又要发送tcp数据的时候,不再发送两次了,而是合成一份发送,这种情况下就叫做捎带应答。
就类似于我们平时说话,你说吃了吗,朋友说吃了, 你吃了吗。 这种情况就是朋友将应答”吃了“和tcp数据”你吃了吗“合在了一起。即为捎带应答。
另外一个知识点就是超时重传。
超时重传
下面是tcp最基本, 最原本的通信过程:
上面这种,一端发送数据,另一方进行应答。双方都发送数据,双方都进行应答,就能保证两个方向上的可靠性。
另外,对于双方来说,如何确认一条消息对方没有收到呢?难道要一直等着对方的应答吗? 要知道,如果确认到对方没有收到应答后,就应该重传数据了。 所以一直等待对方的应答是不合理的。所以,一段时间后,如果没有收到应答,双方就会认为数据丢失,就要重新发送数据。——即为,超时重传。
32位序号
先来思考一下,世界上存不存在100%可靠的网络协议?
确认应答机制,有一个现象,就是我收到了应答,那么我就能保证应答之前的最新的发送的消息是被对方收到了。没有应答的数据,我们无法保证可靠性。
所以,最新的一条消息,是没有应答的。在人类世界里,我们无法保证发送出去的消息是100%可靠的!所以,从全局的角度上,我们这个世界上是不存在100%可靠的协议的但是能保证局部上的消息的可靠性(最新消息之前的消息的可靠性。)
一个发送,一个应答,效率是非常低下的。通常我们的客户端向服务器发消息,一次是发一批消息。
但是, 这里有一个问题, 我们的服务器按顺序把它发出,服务器是否按顺序把它接受呢?
就像一开始一群人在东北,现在要去广东。是否到达广东的顺序就是这群人离开东北的顺序呢。答案是不是的,有些人是坐飞机过去,有些人坐火车过去,有些人坐客车过去。有些人可能虽然出发的比较晚,但是人家是做飞机过去的,有些人虽然出发比较早,但是他是坐或者过去的。坐飞机的就有可能比坐火车的先到目的地。
所以,服务器按顺序发出信息,并不一定是按照顺序接收到。 这就导致了一个问题一一数据包乱序问题。
乱序本身就是不可靠的一种,所以,每一个tcp报头里,会包含一个序号的东西一就是这个32位序号。这个32位序号,就是保证数据的按序到达。
下面就是32位序号:
32位确认序号
假如我今天一次给对方发送了多个报文,那么对方一定也要给我多个响应。我怎么知道响应对应的是哪一个报文呢?
所以tcp为了区分响应对应的是哪一个报文的响应,就有了32位确认序号的概念。
确认序号,填充的是,收到报文的序号 +1。
为什么要这么规定,确认序号的意义: 表示确认序号之前的数据,我已经全部收到了!!!
下一次发送请从确认序号指定的数字开始发送、就是说,客户端发送的序号是1000,那么服务端响应的序号就得是1001。
这样做的意义是什么?
这样做是为了允许应答有少量的丢失、就发送的数有100,200,300,那应只有3001,但是没有10012001但是不需要重传,默认就认为3001%前的报文全都响应了。
为什么要有两种序号
我们知道,请求是有数据的,用的是32位序号,然后响应是没有数据的,用的是32位确认序号。但是,为什么不直接只使用32位序号或者32位确认序号呢?为什么非要用两种序号呢?
原因就在于客户端给服务器发消息,服务器要给我应答,服务器应答,可能只是应答,也可能是指捎带应答。应答就是纯报头,只是用32位确认序号,捎带应答就是要有数据,并且捎带应答因为也有数据,所以就要有32位序号。也就是说,因为一个报文,他可能有双重身份,既可能是应答,也可能是带有数据,所以序号和确认序号有可能同时存在,所以协议里面必须把这两个分开,不能复用。
——————以上就是本节全部内容哦, 如果对友友们有帮助的话可以关注博主, 方便学习更多知识哦!!!