设为首页 加入收藏

TOP

TCP 详解(一)
2019-09-17 18:43:13 】 浏览:47
Tags:TCP 详解

计算机网络中比较中要的无非就是 TCP/IP 协议栈,以及应用层的 HTTP 和 HTTPS 。
前几天一直炒的的比较火的就是 HTTP/2.0 了,但是其实 HTTP/2.0 早在2015年的时候就已经出来了,并且这个版本是基于 Google 公司的 SPDY 协议发布的,其实说白了就是用的 SPDY 做了一点修改。
好了今天的主题是 TCP 就不过多的介绍 HTTP/2.0 了,以后会专门写一篇关于 HTTP/2.0 的文章,介绍一下他的新特性。

1.引言

??我们都知道 TCP 是位于传输层的协议,他还有一个兄弟就是 UDP ,他们两共同构成了传输层。显然他们之间有很大的区别要不然的话在传输层只需要一个就好了。

??其中最重要的区别就是一个面向连接另外一个不是,这个区别就导致了他们是否能够保证稳定传输,显然不面向连接的 UDP 是没办法保证可靠传输的,他只能靠底层的网络层和链路层来保证。我们都知道网络层采用的是不可靠的 IP 协议。好吧,网络层也保证不了可靠传输,所以 UDP 保证可靠传输只能依靠链路层了。

??而 TCP 就好说了他不仅仅有底层的链路层的支持,还有自己的面向链接服务来保证可靠传输。当然 TCP也不仅仅就是比 UDP 多了一个可靠传输,前面也说到了这只是他们之间一个重要的区别。其实他的三个重要特性就是它们之间的区别。

??* 可靠传输
??* 流量控制
??* 拥塞控制

2.可靠传输

TCP 主要是确认重传机制 数据校验 数据合理分片和排序 流量控制 拥塞控制依靠来完成可靠传输的 , 下面详细介绍这几种保证可靠传输的方式。

1. 确认和重传

确认重传,简单来说就是接收方收到报文以后给发送方一个 ACK 回复,说明自己已经收到了发送方发过来的数据。如果发送方等待了一个特定的时间还没有收到接收方的 ACK 他就认为数据包丢了,接收方没有收到就会重发这个数据包。

好的,上面的机制还是比较好理解的,但是我们会发现一个问题,那就是如果接收方已经收到了数据然后返回的 ACK 丢失,发送方就会误判导致重发。而此时接收方就会收到冗余的数据,但是接收方怎么能判定这个数据是冗余的还是新的数据呢?

这就涉及到了 TCP 的另外一个机制就是采用序号和确认号,也就是每次发送数据的时候这个报文段里面包括了当前报文段的序号和对上面的报文的确认号,这样我们的接收方可以根据自己接受缓存中已经有的数据来确定是否接受到了重复的报文段。这时候如果出现上面所说的 ACK 丢失,导致接受重复的报文段时客户端丢弃这个冗余的报文段。

好现在我们大致了解了确认重传机制,但是还有些东西还没有弄清楚,也就是 TCP 真正的实现究竟是怎样的。

  1. 确认是每发一个报文段就确认一次还是一次确认多个呢?

  2. 还有上面所说的发送方等待一个特定的时间,这个时间究竟等多长比较合适?
  3. 重传的时候是只重传那个没收到的报文还是重传那个报文段及它以后的报文段?

    1.累计确认/单停等协议

    这就是我们要解决的第一个问题就是如何确认。这里涉及到两种确认方式,分别称为累计确认(捎带确认)单停等协议

    单停等协议

用一张图来快速理解,就是每发送一次数据,就进行一次确认。等发送方收到了 ACK 才能进行下一次的发送。

累计确认

一样的也是采用的 ACK 机制,但是注意一点的是,并非对于每一个报文段都进行确认,而仅仅对最后一个报文段确认,捎带的确认了上图中的 203 号及以前的报文。

总结:从上面可以看到累计确认的效率更加高,首先他的确认包少一些那么也就是在网络中出现的大部分是需要传输的数据,而不是一半的数据一半的 ACK ,然后我们在第二张图中可以看到我们是可以连续发送多个报文段的(究竟一次性能发多少这个取决于发送窗口,而发送窗口又是由接受窗口和拥塞窗口一起来决定的。),一次性发多个数据会提高网络的吞吐量以及效率这个可以证明,比较简单这里不再赘述!

结论:显然怎么看都是后者比较有优势,TCP 的实现者自然也是采用的累计确认的方式!

2. 超时时间计算

上文中的那个特定的时间就是超时时间,为什么有这个值呢? 其实在发送端发送的时候就为数据启动了一个定时器,这个定时器的初始值就是超时时间。

超时时间的计算其实有点麻烦,主要是我们很难确定一个确定的值,太长则进行了无意义的等待,太短就会导致冗余的包。TCP 的设计者们设计了一个计算超时时间的公式,这个公式概念比较多,有一点点麻烦,不过没关系我们一点点的来。

首先我们自己思考如何设计一个超时时间的计算公式,超时时间一般肯定是和数据的传输时间有关系的,他必然要大于数据的往返时间(数据在发送端接收端往返一趟所用的时间)。好,那么我们就从往返时间下手,可是又有一个问题就是往返时间并不是固定的我们有如何确定这个值呢?自然我们会想到我们可以取一小段时间的往返时间的平均值来代表这一时间点的往返时间,也就是微积分的思想!

好了我们找到了往返时间(RTT),接下来的超时时间应该就是往返时间再加上一个数就能得到超时时间了。这个数也应该是动态的,我们就选定为往返时间的波动差值,也就是相邻两个往返时间的差。

下面给出我们所预估的超时时间(TimeOut)公式:

TimeOut = AvgRTT2 + | AvgRTT2 - AvgRTT1 |

很好,看到这里其实你已经差不多理解了超时时间的计算方式了,只不过我们这个公式不够完善,但是思路是对的。我们这时候来看看 TCP 的实现者们采用的方式。

RTT_New = (1-a)RTT_Current + a*Avg_RTT (计算平均 RTT,a 通常取0.125)
DevRTT = (1-b)DevRTT + b|RTT_New - Avg_RTT|  (计算差值,b 通常取0.25)
TimeOut = RTT_New + 4*DevRTT (计算超时时间) 

好的,这就是 TCP 实现的超时时间的方式,但是在实际的应用中并不是一直采用的这种方式。假如说我们现在网络状态非常的差,一直在丢包我们根本没必要这样计算,而是采用直接把原来的超时时间加倍作为新的超时时间。


总结:好的现在我们知道了在两种情况下的超时时间的计算方式,正常的情况下我们采用的上面的比较复杂的计算公式,也就是 RTT+波动值 否则直接加倍

3. 快速重传

上面我们看到在发送方等待一个超时重传时间后会开始重传,但是我们计算的超时重传时间也不定就很准,也就是说我们经常干的一件事就会是等待,而且一般等的时间还挺长。那么可不可以优化一下呢?

当然,在 TCP 实现中是做了优化的,也就是这里说到的快速重传机制。他的原理就是在发送方收到三个冗余的 ACK 的时候,就开始重传那个报文段。那么为什么是三个冗余的 ACK 呢?注意三个冗余的 ACK 其实是四个 ACK 。我们先了解一下发送 ACK 策略,这个是 RFC 5681 文档 规定的。

  1. 第一种情况收到一个期望的有序的数据时,最多延时 500ms 发送一个 ACK 表示该数据及以前的数据都收到了。

  2. 第二种情况是收到一个期望的有序的数据时,前面的有序数据等待发送 ACK 的时候立即发送一个 ACK 捎带确认前面那个数据,也就是第一个数据还在延时的时候又来一个那么久两个一起确认。

  3. 第三种情况,收到比期望序号大的数据的时候立即发送冗余 ACK ,ACK 确认的值就是中间缺少的第一个序号的值。

  4. 收到能部分填充或者完全填充中间缺少的数据的,如果这个报文是起始于缺少的数据的低端就立即发送一个 ACK。

好的,那么现在我们可以看到如果出现了三个冗余的 ACK 他只可能

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇linux mysql数据库安装 下一篇数据系统的未来------《Designing..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目