深入理解TCP网络协议(3)

目录

1.前言

2.流量控制

2.阻塞控制

3.延时应答

4.捎带应答

5.面向字节流

6.缓冲区

7.粘包问题

8.TCP异常情况

9.小结


1.前言

在前面的博客中,我们重点介绍了TCP协议的一些属性,有连接属性的三次握手和四次挥手,还有保证数据安全的重传机制和确认应答,还有为了提高效率所用的滑动窗口等.然而TCP协议的特性远不止这些,在这篇博客中,我们将更深入的了解决TCP协议的其它特性.

2.流量控制

滑动窗口我们知道是用来提升传输效率的,这个窗口如果越大的话,那么自然传输效率也就越高,那么这个窗口可以无限增大吗?答案是否定的,首先从接收方的角度来看,接收方是有接收缓冲区的,如果这个窗口过大,发的数据过多,极有可能把这个缓冲区占满,那么就会引起一系列的问题.站在发送方的角度来看,也不能一次发送太多数据,因为我们不知道路上的网络线路是否通畅,能不能一次承担这么多的数据而不损失稳定性(这个我们一会在介绍).

首先我们站在接收方的角度,其实接收方返回给发送方的ACK报头里面,是有一个窗口大小属性的,这个属性的大小取决于接收缓冲区剩余的内存大小.我们来画图说明一下.

有了接收方这个窗口大小这个字段,发送方就知道自己一次性发送多大的数据合适,就可以进行不影响可靠性的前提下提升效率了.

2.阻塞控制

在前面我们提到过,不仅仅是接收方要进行流量控制,告诉发送方要发多大的.在发送方这里,由于物理线路的影响,我们也得知道我们发送多大的合适,那么在TCP协议里,是如何知道网络的情况,以决定我们发送多大的数据合适呢?

这就要讲到我们的阻塞控制了. 我先来说一下基本的原理,我们可以先呈指数倍的发送数据,看有没有ack响应,如果都没问题的话,到了一定的阈值,我们可以在逐渐增大,一直到有数据丢失了(即没有收到ack,说明网络线路出问题了,可能到了它能承受的最大值,我们就接着降下去,在逐渐增大. 这是一个动态平衡的过程.这种思绪想是一种实验的方式来测试.

当TCP开始启动的时候,慢启动阈值等于窗口最大值;

在每次超时重发的时候,慢启动阈值会变成原来的一半,同时拥塞窗口置回1;

少量的丢包,我们仅仅是触发超时重传;大量的丢包,我们就认为网络拥塞;

当TCP通信开始后,网络吞吐量会逐渐上升;随着网络发生拥堵,吞吐量会立刻下降;

拥塞控制,归根结底是TCP协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案

还有一个问题就是,我们到底是根据发送方的阻塞控制来确定窗口大小,还是根据接收方的流量控制来决定呢?

事实是,哪个小我们就遵守哪个.有点类似于木桶效应

3.延时应答

如果接受数据的时候立即响应ack,这时候返回的窗口可能就比较小,为了解决这种问题.TCP协议内部还有一个延时应答的机制.

假设接收端缓冲区为1M。一次收到了500K的数据;如果立刻应答,返回的窗口就是500K;

但实际上可能处理端处理的速度很快,10ms之内就把500K数据从缓冲区消费掉了;

在这种情况下,接收端处理还远没有达到自己的极限,即使窗口再放大一些,也能处理过

来;

如果接收端稍微等一会再应答,比如等待200ms再应答,那么这个时候返回的窗口大小就是

1M

事实上,这个时间的延时在用户眼里是非常小的,所以我们完全可以为了提升传输效率(返回的窗口大一些)使用延时应答机制.我们的目的是确保网络不拥堵的情况下,尽量提高传输效率.

那么所有的包都可以延迟应答么?肯定也不是;

数量限制:每隔N个包就应答一次;

时间限制:超过最大延迟时间就应答一次;

具体的数量和超时时间,依操作系统不同也有差异;一般N取2,超时时间取200ms

4.捎带应答

在延迟应答的基础上,我们发现,很多情况下,客户端服务器在应用层也是 "一发一收" 的。意味着客户端给服务器说了 "are you ok?",服务器也会给客户端回一个 "very ok";

那么这个时候ACK就可以搭顺风车,和服务器回应的 "very ok" 一起回给客户端

5.面向字节流

TCP协议发送和接收的数据都是面向字节流的,我们可以给它传入一个byte数组,把我们想要的数据给转化成二进制的形势发送过去.接收的时候在转成对应的格式即可.

6.缓冲区

创建一个TCP的socket,同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区;

调用write时,数据会先写入发送缓冲区中;

如果发送的字节数太长,会被拆分成多个TCP的数据包发出;

如果发送的字节数太短,就会先在缓冲区里等待,等到缓冲区长度差不多了,或者其他合适

的时机发送出去;

接收数据的时候,数据也是从网卡驱动程序到达内核的接收缓冲区;

然后应用程序可以调用read从接收缓冲区拿数据;

另一方面,TCP的一个连接,既有发送缓冲区,也有接收缓冲区,那么对于这一个连接,既

可以读数据,也可以写数据。这个概念叫做 全双工

由于缓冲区的存在,TCP程序的读和写不需要一一匹配,例如:

写100个字节数据时,可以调用一次write写100个字节,也可以调用100次write,每次写一

个字节;

读100个字节数据时,也完全不需要考虑写的时候是怎么写的,既可以一次read 100个字

节,也可以一次read一个字节,重复100次

7.粘包问题

TCP协议没有像UDP 一样有一个报文长度这样的字段,但是有一个序号这个字段.在传输层的角度,TCP报文是一个一个传输过来的,排列好的数据在缓冲区中,但是在应用层的角度,只是看到了一连串的字节数据,那么应用层看到的这些数据,就不知道应该从哪一部分到哪一步部分是一块的, 是不是一个完整的应用层数据报.

如何解决这个问题呢?我们三种方案

1.对于定包的长,我们每次都读取固定大小的的数据即可,

2.对于边长的包,我们可以在包头设置一个总包长度的字段,从而就知道了包结束的位置.

3.我们也可以在包和包中间使用明确的分隔符(应用层协议是程序员自己约定的,只要不影响数据,即正文的数据不和这个分隔符冲突久可.

粘包问题只是在TCP协议中会出现,并不会在UDP中出现,这是因为UDP是把英国摇滚乐数据交给应用层,要么收到完整的数据报,要么不收,不会出现半个的问题.所以不会有粘包问题.

8.TCP异常情况

我们知道TCP是有连接的,那么在出现异常的时候,TCP是如何断开连接的呢?我们分别来说明

进程中止:进程中止会释放文件描述符,仍然可以发送断开连接的FIN,和正常关闭没啥区别.

机器重启:重启的时候也会释放文件描述符,所以和进程中止的情况一样.

机器断网/断电:

1.如果断电的是接受方,发送方会发现没有ack了,会重传,重传几次还是不行, 就会进行复位操作,(相对于清楚原来的TCP中的临时数据重新开始)会用到RST这个复位报文段(和ack,fin,syn这些一样的报文段,另外,PSH是催促对方快点给我发消息,URG是TCP外带数据,语言写特殊的数据报会携带一些特殊功能的数据) 此时是RST也不会有ack,这个时候发送方就会单方面放弃连接.

2.如果是发送方接收了,发送方迟迟等不到数据,他会发送一个"心跳包",来询问对方的情况,如果这个"心跳包"一直没有得到回应,自然也会单方面释放连接了,这个心跳包是一个周期性的,如果没有心跳就会认为对端挂了,在以后的分布式系统中,服务器之间的互相调用也需要心跳包来确定存货状态.

9.小结

其实TCP协议非常复杂,它不仅仅是有我们前面几篇博客和这篇博客中强调的特性,还有其它的特性,希望各位大佬程序员这条路的修炼中,刻苦钻研,努力发掘.让自己的技术和对底层的 理解更上一层楼.

相关推荐
sunfove1 小时前
光网络的立交桥:光开关 (Optical Switch) 原理与主流技术解析
网络
Kevin Wang7274 小时前
欧拉系统服务部署注意事项
网络·windows
min1811234564 小时前
深度伪造内容的检测与溯源技术
大数据·网络·人工智能
汤愈韬4 小时前
NAT策略
网络协议·网络安全·security·huawei
汤愈韬4 小时前
Full Cone Nat
网络·网络协议·网络安全·security·huawei
zbtlink5 小时前
现在还需要带电池的路由器吗?是用来干嘛的?
网络·智能路由器
桌面运维家5 小时前
vDisk配置漂移怎么办?VOI/IDV架构故障快速修复
网络·架构
dalerkd5 小时前
忙里偷闲叙-谈谈最近两年
网络·安全·web安全
汤愈韬6 小时前
NAT ALG (应用层网关)
网络·网络协议·网络安全·security·huawei
运维栈记7 小时前
虚拟化网络的根基-网络命名空间
网络·docker·容器