文章目录
TCP协议格式
格式:
上面的这个TCP的格式就多了
源端口和目的端口
这个和UDP的协议的端口一样,只不过这个的范围变大了
报文长度和保留
这个报文长度只有4个bit位,范围就是从0~15,单位是4字节
如果里面的内容是1111,其实真正的报文的长度是15*4=60个字节
保留也是为了增加bit位的,如果以后报文长度增加了,就可以使用报文长度+保留来一起计算报文的真正长度了
可靠传输
一、确认应答
确认应答就是可以知道对方有没有接受到消息,如果接受到了就返回一个应答报文(ACK)表示已经接收到了。确认应答是可靠传输的关键。
序号和确认序号
当发送多个消息的时候,在消息的传输的过程中,可能会发生先发出的消息却后被收到的情况.
这时候回复的时候就会乱套了,那么TCP协议是怎么实现确认应答机制的呢
TCP提出了一个序号和确认序号:
要发送的数据占用一定数量的字节,将数据按照字节来进行编号,一个字节对应一个编号.
第一个字节就是序号1,第2个字节就是序号2,…第1000个字节就是序号1000
把数据都对应好相应的字节序号之后,我们就根据这个序号来进行传输和应答了
主机a发送序号1~1000的数据,也相当于是从序号1开始,一共发送1000个字节的数据
主机b返回一个应答(ACK),1001,表示1001号之前的字节它都已经收到了
主机a就根据主机b返回的1001从它开始传输1000个字节的数据,也就是1001~2000
主机b在返回2001,表示从1~2000之间的数据它都已经收到了
通过堆数据进行编号和相应的时候返回编号我们就成功的实现了对每一条数据都有一个ack应答,这样就不用害怕回答不匹配的信息了
二、超时重传
上面是传输成功的情况,可以收到正常的应答,但是还有没有正常收到应答的情况,超时重传就是解决这样的问题的.
丢包的两种情况
应答不成功的主要有下面的两种情况:
一.传输的数据的时候丢包
二.ACK返回失败
发送方的重传步骤
现在介绍一下发送方是怎么通过tcp的socket的api发送消息并且重传消息的
发送消息:
socket的api中的write操作将要发送的消息写到"发送缓冲区"中,操作系统内核从发送缓冲区中取数据,然后经过网卡进行封装,发送给接收方
没有正常收到ACK回应报文:
如果消息的发送方没有接收到ack,就要重传消息.
此时发送缓冲区还是上一条数据,操作系统直接从发送缓冲区中拿走数据,通过网卡进行封装后,再一次的发给接收方.
如果收到了ACK报文:
发送方的发送缓冲区中的数据就会被清除
接收方的接收重传
因为造成发送方没有正常的接收到ack有两种情况,一种是消息没有到达接收方,另一种是ack传输的时候丢失.
对于第一种情况,接收方没有收到消息,发送方直接再发送一次此消息即可
但是对于第二种情况,接收方就会收到两个一样的消息,如果是取钱消息,接收方就会收到两次取钱的消息,这样就会发生错误,那我们应该怎么办呢?
对于接收方来说,它同样有一个接收缓冲区,收到的消息都会先来到这个接收缓冲区中,这个缓冲区其实也是一个堵塞队列.
对于来到的消息,它会根据上面的序号来判断是不是相同的消息
如果是相同的消息,它就会丢弃
如果不是相同的消息,它就会纳入
使得socket api的read操作读取到的一直都是不重复的消息!这个堵塞队列极其重要
重传次数
重传之后就一定可以成功吗,一定可以收到ack的回答吗?
答案当然是不会的,如果网断了,再怎么重传都是没有结果的.
所以,我们也不能一个劲的进行重传,重传的时间间隔和次数都是有要求的
- 如果重传的次数超过了一定值,就会放弃重传
- 每次重传的时间间隔都会增大
对于一个消息,如果丢包的几率是20%,那么两次重传的几率就变成了4%,所以之后的重传也就没有必要了
三、连接管理🔑
这个是TCP的可靠传输中最引以为傲的一个特性,也是TCP最出名的一点,三次握手,四次挥手谁不知道呀😎
连接管理主要有一下的两点:
- 建立连接
- 断开连接
所以下面我们就来看一看这个三次握手吧:
1.三次握手
三次握手就是先确认一下客户端和服务器的接收消息和发送消息的功能是不是都是好使的,也就是先投石问路的过程,先确认好是不是都可以了,为以后的正式的消息的传输做好准备.
- 三次握手的过程
- 客户端先对服务器发送一个syn
- 服务器会对收到的syn回应一个ack进行回应,同时也返回一个syn
- 客户端对收到的syn返回一个ack
这个就是三次握手的过程.
下面就具体的分析一下每一步都做了什么:
客户端要确定自己和服务器的发送消息和接受消息是好的,
服务器要确定自己和客户端的发送消息和接受消息是好的.
步骤就是:以client向server握手为例
- 客户端发送了syn,test客户端的发送和服务器的接收情况如何
- 服务器正常接收到了消息的话,服务器就知道客户端发送和服务器接收正常
- 服务器返回ack=x+1,客户端就知道了客户端发送和服务器接收都正常
- 服务器还返回了syn,test服务器发送和客户端的接收情况如何
- 客户端正常接收到了消息的话,客户端就知道服务器的发送和客户端的接收正常
- 客户端返回ack=y+1,服务器就知道服务器发送和客户端接收正常
总结的规律:
A发送syn进行test-------->B知道A正常-------->B发送ack告知A---------->A知道自己正常
上面的三次握手就是
synX—>ackX+1,synY----->ackY+1
TCP的状态
tcp的状态有很多:下面主要介绍两个listen和establish
listen:表示服务器已经配置好自己的端口号和IP地址,可以有服务器来进行建立连接了(三次握手)
establish:表示连接建立成功,服务器可以和客户端进行正式的通信了
如何表示SYN和ACK
那么在TCP的报文中是怎么体现syn报文还是ack报文呢?
我们就用上面这个状态表表示,
如果是ack就在ack那里填1,其余的地方填0
如果是syn就在syn那里填1,其余的地方填0
如果ack和syn,就同时在syn和ack那里填1,其余地方填0
上面我们说过,三次握手的第一个作用就是投石问路,先谈谈路,看看客户端和服务器之间可以不可以进行通信.
第二个作用就是服务器和客户端有时候会对一些参数进行一下协商,会对一些内容进行交互.
这些内容会在以后进行说明
还有一个问题就是进行两次握手,四次握手可以吗
两次握手是绝对不行的,因为缺少最后一个ack的话,服务器不知道自己的发送功能和客户端的接收功能是不是正常的
四次握手虽然是可以但是不提倡,因为一次发送两个消息比两次分发消息高效.不会重复的封装.
2.四次挥手
上面的三次握手是建立连接的,连接建立好之后服务器和客户端之间就会用特定的数据结构保存各自的五元组.
但是当我们断开连接的时候,这时候保存的五元组的数据也就没有用处了.所以我们就要进行四次挥手来断开连接,删除数据.
流程
- 当客户端执行到socket 的api的close函数的时候,客户端向服务器发送一个FIN请求,
- 服务器接收到操作系统内核就立刻发送一个ACK应答服务器发送完应答之后就进入了**CLOSED_WAIT状态,**直到执行到服务器的close函数
- 执行到服务器的close函数之后,服务器就行客户端发送一个FIN请求
- 客户端接收到请求之后操作系统内核就立刻发送一个ACK应答客户端在发送完应答之后进入TIME_WAIT状态还要再等待2*MSL段时间,因为害怕最后一个ack丢包,重传的时候还需要客户端再次发送ACK应答呢,所以客户端还要再等待一段时间.
四、滑动窗口
虽然TCP协议保证了可靠性传输,但是对于传输效率的话TCP也是很有保证的,就是即包装了传输的效率,又保证了传输的安全性,TCP协议做的还是很全面的。
那TCP是怎么包装传输的效率呢?就是在较短的时间内多发送几条报文
以往的传输
之前我们的传输都是上面这样子的,发送一个TCP报文就等待它的ACK回应之后再发,发一个等一个,发一个等一个.如果发消息和确认消息都是1分钟的话,那么发五条消息和确认五条消息就花费了10分钟。
但是滑动窗口可不是这样发的:
先连续的发送N条消息,当收到发送的N条消息的任意一条确认消息的时候,就发送一条新的消息
就像下面这样:
像上面这样就是在十分钟之内收到了5条应答消息和10条数据,传输的效率大大的提升了.
那么是怎么显示出滑动窗口的呢?
一次发送的数量N,就是窗口的大小,需要等待的应答报文就是窗口中的主要内容.
随着收到的应答报文和新发送的数据,要接受的回应报文的序号就是滑动窗口的范围
收到回应报文----->发送一条新的数据------->滑动窗口向后移动一位
丢ACK报文
上面我们提到过,在消息的传送过程中会有丢包的现象存在,下面我们看看如果在回传的过程中丢了ACK报文会怎么样
所以像上面这种情况,前面丢失的报文不用担心,只要我们收到了后面的那些报文就自动的表示前面的数据已经收到了,就算是之前的报文丢到了也是没有关系的,后面的可以显示就可以证明了,前面的丢了也无所谓了
丢传输的数据
但是如果我们是丢了传输的数据的话,就麻烦了
如果我们的其中一个范围10012000的数据在传输的过程中丢失,那么回应的报文的序号应该始终是1001,表示只接受到了11000之前的数据,而不会像之前我们分析丢ack那样返回2001,应为这次是数据丢失了
所以,当其中的10012000丢失了之后,在发送其他范围的数据都会显示只接到了11000之间的数据
此时主机B的接受缓冲区的内容是这样子的:
其他的传过来的数据都接受到了,只是缺少了1001~2000的.
所以,当我们接受到多次1001序号的回应报文之后,主机A就会触发超时重传的机制,再重新的发送一次该数据
补上该数据之后我们就可以直接返回7001报文了,表示1~7000的数据都接受到了
五.流量控制
流量控制是滑动窗口的问题,上面我们说过,窗口的大小也就是N值的大小,这个N值越大传输的就越快,但是我们不可以一味的增大窗口,而是要根据接收方的接收缓冲区的剩余值来控制这个N的大小,这就是流量控制
16位窗口大小
N的值是随着接收方的接收缓冲区里面的空间而进行变换的.
如果接收缓冲区中的空间所剩无几了,那么发送方就少发送一些数据,窗口的值就小
如果接收缓冲区中的空间还剩下了很多,那么发送方就可以多发送一些数据,窗口的值就大
那我们是怎么使接收方知道我们的缓冲区的空间的数据呢?
就可以使用TCP的报文的16位窗口大小+(选项)来告诉发送方,这样的话发送方就可以根据这个窗口的大小来调整发送的报文的数量.
但是当窗口为0的时候我们就一定不发了吗,万一接收缓冲区的大小变大 了呢?
所以发送方有又了一招,就是会进行不停的窗口探测,应答方就会返回当前的窗口的大小的信息,如果窗口变大了,发送方就可以继续的发送消息了,所以这个窗口探测也是非常的重要的
六、拥塞控制
上一节流量控制是接收方的接收能力对发送方的传输数量的限制。
这一节是接收方和发送方之间的链路层对发送方的传输数量的限制。
也就是说接收方的处理能力对流量窗口的大小的控制——流量控制
传输之间的链路对拥塞窗口的大小的控制——拥塞控制。
最终滑动窗口的大小是上面两个窗口流量窗口和拥塞窗口的最小值
下面我们就来具体的看一下拥塞控制到底是怎么样的:
- 首先,从最小的拥塞窗口开始
- 接着,拥塞窗口就以指数的方式来进行扩张,直到到达阈值为止为什么要使用指数增长呢?因为我们要快速的到达传输效率最高的窗口的大小
- 到达阈值之后为了防止窗口过大而丢包,所以就进行线性增大,因为这个范围的窗口是传输的效率最高的
- 当发生堵塞的时候,有两种TCP版本,一个是快恢复的版本,一个是慢开始的版本快恢复:此时窗口从新的阈值开始线性增加——这个阈值是发送堵塞的窗口的一半 因为最理想的传输窗口的大小就是再阙值和丢包值之间慢开始:此时窗口直接就从最小的堵塞窗口开始,再重新进行指数+线性的方式。 这样的好处就是保证丢包的概率最小,保证包一定是可以传输过去的 而且此时慢开始的阙值就是丢包的窗口的大小的一半
七、延时应答
延时应答也是流量控制的一种延申,每次发送方向接收方的接收缓冲区中探测它的剩余空间的大小的时候。接收方晚一点回复空间大小就是延时应答。
所以,晚一点返回消息,等待一段时间之后,空间的剩余会更加大一些
八、捎带应答
捎带应答是延时应答的延伸版本。
对于客户端和服务器来说,可以有下面几种方式:
一问一答,一问多答,多问一答,多问多答
所以,当一个请求从发送方请求的时候,接收方可能会做出下面的响应:
ack报文和业务报文
ack报文是立即返回的,业务报文是要等待代码执行到才返回的,
所以不是同时返回这两个报文的
但是当我们延时应答之后,这两个报文可能时间上就一同返回了
所以,一次返回两条报文的效率比较高,所以这个就是捎带应答
九、粘包问题
在发送方将多个数据发送到接收缓冲区的时候,多个数据连在一起就会发送粘包的问题。
对于发送方发来的TCP报文,到达接收缓冲区的时候被分用后其实只剩下了数据
接收方就使用read函数来读取字节,但是读取到的其实是黏在一起的字节.这个就是粘包问题.
那么我们如何来解决这个问题呢?这个其实是应用层的问题
只需要应用层在数据的末尾加上一个分隔符; 就将不同的数据分隔开了,这样就解决了问题了
TCP的异常情况
进程终止
就是直接将进行任务的这个进程终止了,在这个时候TCP是什么样子的呢?
TCP连接就是通过socket来打开的文件,本质上就是打开文件而已.
所以每一次打开一个文件就是增加PCB,里面的一个文件描述符表
每次删除一个文件都是删除文件描述符表
所以当我们强制的将进程终止的时候,就是PCB删除了,也就是将这个文件描述符表删除了
和我们调用socket.close()函数的效果是一样的,都会触发四次挥手
机器关机
机器关机其实和进程终止一样,机器关机之前会将所有的进程全部都杀死
掉电断网
如果直接掉电断网了,那么这个就是突然性的问题了
- 如果服务器挂了
服务器挂了,客户端发送消息之后一直都等不到ack回应.
所以客户端就会进行超时重传
但是超时重传还是没有响应
客户端重新建立连接之后,如果还是没有响应就是直接断开连接
- 如果客户端挂了> 服务器会给客户端发送一个不带有任何数据的一个探测包,也叫做心跳包.> > 如果不可以收到服务器的ack之后,也会进行超时重传,如果超时重传还是没有响应就进行重新连接,如果重新连接失败就直接断开连接
TCP和UDP
- TCP属于可靠性比较高
- UDP属于传输效率比较高如果保证UDP实现可靠性?> 在应用层实现TCP的机制
版权归原作者 CAFE~BABE 所有, 如有侵权,请联系我们删除。