共计 4457 个字符,预计需要花费 12 分钟才能阅读完成。
一、TCP 协定简介
1、数据包的发送流程
一个数据包,从聊天框里收回,音讯会从聊天软件所在的用户空间拷贝到内核空间的发送缓冲区(send buffer),数据包在传输层增加一个 TCP 头部、在网络层增加一个 IP 首部,进入到数据链路层增加一个首部和尾部,将其封装为帧,在这里数据包会通过流控(qdisc),再通过 RingBuffer 发到物理层的网卡。数据就这样顺着网卡发到了纷繁复杂的网络世界里。这里头数据会通过多个路由器和交换机之间的转发和跳转,最初达到目标机器的网卡处。
此时目标机器的网卡会告诉 DMA 将数据包信息放到 RingBuffer 接收缓冲区中,再触发一个硬中断给 CPU,CPU 触发软中断让 ksoftirqd 去 RingBuffer 轮询收包,于是一个数据包就这样顺着物理层,数据链路层,网络层,传输层逐层解封,最初从内核空间拷贝到用户空间里的聊天软件里。
数据从发送端到接收端,链路很长,任何一个中央都可能产生丢包,简直能够说丢包不可避免。
那数据包的牢靠传输是如何保障的呢?
2、TCP 协定在五层模型中的地位
计算机网络体系结构中的物理层、数据链路层和网络层,它们独特解决了将主机通过异构网络互联起来所面临的问题,实现了主机到主机的通信。
网络层的 IP 协定实现了路由性能,容许某个局域网的 A 主机,向另一个局域网的 B 主机发送音讯,而它并不保障数据包的残缺。
如何为运行在不同主机上的利用过程提供间接的逻辑通信服务,就是运输层的次要工作。
TCP 协定位于传输层,次要解决数据的牢靠传输的问题。
3、什么是 TCP 协定
TCP 是面向连贯的、牢靠的、基于字节流、全双工的传输层通信协议。
面向连贯:要求正式发送数据之前须要通过「握手」建设一个逻辑连贯,完结通信时也是通过有序的四次挥手来断开连接。
牢靠:无论的网络链路中呈现了怎么的链路变动,TCP 都能保证数据从 A 机器的传输层牢靠地发到 B 机器的传输层;
基于字节流:流的含意是没有固定的报文边界。假如你调用 2 次 write 函数往 socket 里顺次写 500 字节、800 字节。write 函数只是把字节拷贝到内核缓冲区,最终会以多少条报文发送进来是不确定的。
全双工:通信的单方在任意时刻既能够是接收数据也能够是发送数据
二、撑持 TCP 协定的基石 —— 首部字段
1、源端口号、指标端口号
TCP 的报文里是没有源 ip 和指标 ip 的,只有源端口号和指标端口号,因为那是 IP 层协定的事件。
2、序列号
TCP 是面向字节流的协定,通过 TCP 传输的字节流的每个字节都调配了序号,序列号指的是本报文段第一个字节的序列号。用来解决网络包乱序问题。
3、确认号
TCP 应用确认号来告知对方下一个冀望接管的序列号,小于此确认号的所有字节都曾经收到。用来解决丢包的问题。
4、窗口字段
发送本报文段的一方的接管窗口的大小,即接管缓存的可用空间大小,这用来示意接管方的接管能力。
这个字段用来管制发送方的数据发送量,这就是所谓的流量管制。
5、测验和字段
用来查看整个 TCP 报文段在传输过程中是否呈现了误码,如果接管方检测到校验和有过错,则该 TCP 报文段会被间接抛弃。
6、管制位
- ACK:确认位,该位为 1 时,「确认应答」的字段变为无效,TCP 规定除了最后建设连贯时的 SYN 包之外该位必须设置为 1。
- SYN:同步标记位,用于 TCP“三次握手”建设连贯,该位为 1 时,示意心愿建设连贯,并在其「序列号」的字段进行序列号初始值的设定。
- FIN:终止标记位,该位为 1 时,示意今后不会再有数据发送,心愿断开连接。
三、序列号与确认应答机制
TCP 为发送的每个字节都调配了序号,并将每个报文段的第一个序号放到首部的序列号上,以便接管的一方依照程序还原。
确认应答机制就是接管方收到 TCP 报文段后就会返回一个确认应答音讯,示意这个序列号以前的数据曾经收到。
如果在肯定工夫内未收到接管方的确认音讯,发送方就会意识到音讯可能失落,须要进行重传。
四、重传机制
重传机制是为了保障所有的数据包都能够达到。
1、超时重传
TCP 发送方在发送报文的时候,会设定一个定时器,如果在规定的工夫内没有收到接管方发来的 ACK 确认报文,发送方就会重传这个已发送的报文段,如果仍旧没有收到回应,就会持续重传。
超时重传工夫 RTO 的值应该略大于报文往返 RTT 的值,如果超时重传的数据又超时了该怎么办呢?
TCP 的策略是每次间隔时间都是上次工夫的 2 倍。
2、疾速重传
如果发送 5000 个字节的数据包,因为 MSS 的限度每次传输 1000 个字节,分 5 段传输,如下图:
数据包 1 发送的数据失常达到接收端,接收端回复 ACK 1001,示意 seq 为 1001 之前的数据包都曾经收到,下次从 1001 开始发。数据包 2(10001:2001)因为某些起因未能达到服务端,其余包失常达到,这时接收端也不能 ack 3 4 5 数据包,因为数据包 2 还没收到,接收端只能回复 ack 1001。
第 2 个数据包重传胜利当前服务器会回复 5001,示意 seq 为 5001 之前的数据包都曾经收到了。
超时重传是指当发送端收到 3 个或以上反复 ACK,就意识到之前发的包可能丢了,于是马上进行重传,不必傻傻的等到超时再重传,进步了重传效率。
3、SACK
因为除了 2 号包,3、4、5 包也有可能失落,那到底是只重传数据包 2 还是重传 2、3、4、5 所有包呢?
聪慧的网络协议设计者,想到了一个好方法:
- 收到 3 号包的时候在 ACK 包中通知发送端:喂,小老弟,我目前收到的最大间断的包序号是 1000(ACK=1001),[1:1001]、[2001:3001] 区间的包我也收到了
- 收到 4 号包的时候在 ACK 包中通知发送端:喂,小老弟,我目前收到的最大间断的包序号是 1000(ACK=1001),[1:1001]、[2001:4001] 区间的包我也收到了
- 收到 5 号包的时候在 ACK 包中通知发送端:喂,小老弟,我目前收到的最大间断的包序号是 1000(ACK=1001),[1:1001]、[2001:5001] 区间的包我也收到了
这样发送端就分明晓得只用重传 2 号数据包就能够了,数据包 3、4、5 曾经确认无误被对端收到。
这种形式被称为 SACK。
五、流量管制机制
1、基本概念
TCP 会把要发送的数据放入发送缓冲区(Send Buffer),接管到的数据放入接收缓冲区(Receive Buffer),应用程序会不停的读取接收缓冲区的内容进行解决。
如果发送方发送数据太快而导致接管方来不及接管,就容易造成接管方的接管缓存的溢出,也就是数据的失落。
TCP 为应用程序提供了流量管制机制解决该问题,流量管制的根本办法就是接收端会告知客户端本人接管窗口(rwnd),也就是接收缓冲区中闲暇的局部,于是发送端就能够依据这个接收端的解决能力来发送数据,而不会导致接收端解决不过去。
2、流量管制办法——滑动窗口
从 TCP 角度而言,数据包的状态能够分为如下图的四种:
发送窗口是 TCP 滑动窗口的外围概念,它示意了在某个时刻一端能领有的最大未确认的数据包大小(最大在途数据),发送窗口是发送端被容许发送的最大数据包大小,其大小等于上图中 #2 区域和 #3 区域加起来的总大小。
可用窗口是发送端还能发送的最大数据包大小,它等于发送窗口的大小减去在途数据包大小,是发送端还能发送的最大数据包大小,对应于上图中的 #3 号区域。
窗口的左边界示意胜利发送并曾经被接管方确认的最大字节序号。
窗口的右边界是发送方以后能够发送的最大字节序号,滑动窗口的大小等于右边界减去左边界。
当上图中的可用区域的 6 个字节(46~51)发送进来,可用窗口区域减小到 0,这个时候除非收到接收端的 ACK 数据,否则发送端将不能发送数据。滑动窗口变动过程如下:
3、零窗口探测机制
如果发送端的滑动窗口变为 0 了,而且接收端 ACK 的报文段在传输过程中失落了,就会呈现相互期待的死锁场面。
于是乎,TCP 又设计了零窗口探测的机制,用来向接收端探测,你的接管窗口变大了吗?我能够发数据了吗?
直到拿到承受窗口变大的 ACK 就能够持续发送数据了。
六、拥塞管制机制
1、基本概念
在某段时间,若对网络中某一资源的需要超过了该资源所能提供的可用局部,网络性能就要变坏,这种状况就叫拥塞,若呈现拥塞而不进行管制,整个网络的吞吐量就随着负荷的增大而降落。
如果网络上的延时忽然减少,而 TCP 对这个事做出的应答只有重传数据的话,会导致网络的累赘更重,于是会导致更大的提早以及更多的丢包,于是,这个状况就会进入恶性循环被一直地放大。
对此 TCP 的设计理念是:TCP 不是一个自私的协定,当拥塞产生的时候,要做自我牺牲。就像交通阻塞一样,每个车都应该把路让进去,而不要再去抢路了。
2、管制办法
名词解释:
cwnd:拥塞窗口,其值是动态变化的,保护准则是只有网络没有拥塞,就增大,反之就减小
swnd:发送窗口,在拥塞窗口和承受窗口中取小值,前面的解说暂不思考承受窗口,所以 swnd=cwnd
ssthresh:慢开始门限,一般来说 ssthresh 的值是 65535 字节,上面的例子应用 16
当 cwnd < ssthresh 时,应用慢开始算法。当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞防止算法。当 cwnd = ssthresh 时,既可应用慢开始算法,也可应用拥塞防止算法。
2.1、慢开始
刚刚退出网络的连贯,一点一点地提速,慢开始并不慢,这个算法是指数回升的,只是一开始传的数据比拟少
慢开始的算法:
1)连贯建好的开始先初始化 cwnd = 1,表明能够传一个 MSS 大小的数据。
2)每当收到一个 ACK,cwnd++; 呈线性回升
3)每当过了一个 RTT,cwnd = cwnd*2; 呈指数让升
4)当 cwnd >= ssthresh 时,就会进入“拥塞防止算法”
2.2、拥塞防止
每个传输轮次减少 1,这是一个线性回升的算法,使网络没那么容易呈现拥塞
2.3、拥塞算法
1)超时重传,TCP 认为这种状况太蹩脚,反馈也很强烈。
- sshthresh = cwnd /2
- cwnd 重置为 1
-
进入慢启动过程
2)快重传
所谓快重传就是后面介绍的,不等重传计时器超时再重传,发送方一旦收到 3 个间断的反复确认就将相应的报文立刻重传,这样发送方不会呈现超时重传,也就不会误认为呈现了拥塞而谬误的把拥塞窗口 cwnd 的值置为 1
快重传个别与快复原配合应用,发送方一旦收到 2 个反复确认,就晓得当初只是失落了个别报文段,于是不启动慢开始算法,而是执行快复原算法。
2.4、快复原
算法:
- cwnd = cwnd /2
- sshthresh = cwnd
- 开始拥塞防止算法
七、小结
传输层应用 TCP 实现牢靠传输,TCP 为了保障牢靠传输做了很多工作,次要有以下几种:
- 应用序列号和确认应答机制检测数据的发送状态;
- 应用重传机制保障脱漏的数据再次送达;
- 应用滑动窗口来管制发送的速率,防止接收端缓存的溢出导致的数据失落;
- 应用拥塞管制机制来均衡发送数据的大小与拥塞的关系;
TCP 的内容十分多,如有了解不到位或者疏漏的中央,心愿大家的斧正,谢谢!
参考资料
《深入浅出计算机网络》
TCP 的那些事儿(上)
用了 TCP 协定,数据肯定不会丢吗?
深刻了解 TCP 协定: 从原理到实战