<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Tcp/Ip协议 on Lucien's Blog</title><link>https://www.lucien116.com/tags/tcp/ip%E5%8D%8F%E8%AE%AE/</link><description>Recent content in Tcp/Ip协议 on Lucien's Blog</description><generator>Hugo</generator><language>zh-Hans</language><lastBuildDate>Tue, 29 Nov 2016 13:08:31 +0000</lastBuildDate><atom:link href="https://www.lucien116.com/tags/tcp/ip%E5%8D%8F%E8%AE%AE/feed.xml" rel="self" type="application/rss+xml"/><item><title>TCP-IP详解卷1-21：TCP的超时与重传（Timeout and Retransmission）</title><link>https://www.lucien116.com/archives/221/</link><pubDate>Tue, 29 Nov 2016 13:08:31 +0000</pubDate><guid isPermaLink="false">http://www.lucien116.com/?p=221</guid><description>&lt;p&gt;一：介绍
1： 与数据链路层的ARQ协议相类似，TCP使用超时重发的重传机制。
即：TCP每发送一个报文段，就对此报文段设置一个超时重传计时器。
此计时器设置的超时重传时间RTO（Retransmission Time－Out）应当略大于TCP报文段的平均往返时延RTT，一般可取RTO＝2RTT。
但是，也可以根据具体情况人为调整RTO的值，例如可以设置此超时重传时间RTO＝90秒。
当超过了规定的超时重传时间还未收到对此TCP报文段的预期确认信息，则必须重新传输此TCP报文段。&lt;/p&gt;
&lt;p&gt;二：四种定时器
1： 重传计时器（retransmission timer）：当TCP发送报文段时，就创建该特定报文段的重传计时器。可能发生两种情况：
A： 若在计时器截止时间到（通常是60秒）之前收到了对此特定报文段的确认，则撤销此计时器。
B： 若在收到了对此特定报文段的确认之前计时器截止期到，则重传此报文段，并将计时器复位。
2： 坚持计时器（persist timer ） ：为了对付零窗口大小通知，TCP需要另一个计时器。
假定接收TCP宣布了窗口大小为零。发送TCP就停止传送报文段，直到接收TCP发送确认并宣布一个非零的窗口大小。但这个确认可能会丢失。
我们知道在TCP中，对确认是不需要发送确认的。若确认丢失了，接收TCP并不知道，而是会认为它已经完成任务了，并等待着发送TCP接着会发送更多的报文段。但发送TCP由于没有收到确认，就等待对方发送确认来通知窗口的大小。双方的TCP都在永远地等待着对方。
要打开这种死锁，TCP为每一个连接使用一个坚持计时器。当发送TCP收到一个窗口大小为零的确认时，就启动坚持计时器。当坚持计时器期限到时，发送TCP就发送一个特殊的报文段，叫做探测报文段。这个报文段只有一个字节的数据。它有一个序号，但它的序号永远不需要确认；甚至在计算对其他部分的数据的确认时该序号也被忽略。探测报文段提醒对端：确认已丢失，必须重传。
坚持计时器的值设置为重传时间的数值。但是，若没有收到从接收端来的响应，则需发送另一个探测报文段，并将坚持计时器的值加倍和复位。发送端继续发送探测报文段，将坚持计时器设定的值加倍和复位，直到这个值增大到门限值（通常是60秒）为止。在这以后，发送端每隔60秒就发送一个探测报文段，直到窗口重新打开。
3： 保活计时器（keepalive timer ） ：保活计时器使用在某些实现中，用来防止在两个TCP之间的连接出现长时期的空闲。
假定客户打开了到服务器的连接，传送了一些数据，然后就保持静默了。也许这个客户出故障了。在这种情况下，这个连接将永远地处理打开状态。
要解决这种问题，在大多数的实现中都是使服务器设置保活计时器。每当服务器收到客户的信息，就将计时器复位。
保活计时器通常设置为2小时。若服务器过了2小时还没有收到客户的信息，它就发送探测报文段。
若发送了10个探测报文段（每一个相隔75秒）还没有响应，就假定客户出了故障，因而就终止该连接。
4： 时间等待计时器（2MSL timer ）：时间等待计时器是在连接终止期间使用的。
当TCP关闭一个连接时，它并不认为这个连接马上就真正地关闭了。
在时间等待期间中，连接还处于一种中间过渡状态。
这就可以使重复的FIN报文段（如果有的话）可以到达目的站因而可将其丢弃。
这个计时器的值通常设置为一个报文段的寿命期待值的两倍。&lt;/p&gt;
&lt;p&gt;三：拥塞控制用到的术语
数据段：一个数据段就是任意的TCP/IP数据或确认包（或两者兼备）。
发送端最 &lt;a href="http://lib.csdn.net/base/spark" title="Apache Spark知识库"&gt;大数据&lt;/a&gt; 段尺寸（SMSS）:SMSS是发送端能发送的最大数据段的尺寸。这个值是以网络最大传送单元（MTU），MTU路径发现 &lt;a href="http://lib.csdn.net/base/datastructure" title="算法与数据结构知识库"&gt;算法&lt;/a&gt;，RMSS(见下一项)，或其它因素为基础的。该尺寸不包括TCP/IP头和选项。
接收端最大数据段尺寸（RMSS）:RMSS是接收端愿意接收的最大数据段的尺寸。这个值在连接开始时接收端发送的MSS选项中说明。又或者，如果MSS选项没有使用，就是536字节[Bra89].该尺寸不包括TCP/IP头和选项。
满尺寸数据段：一个包括允许最大数目数据的数据段（也就是说，一个包括SMSS字节数据的数据段）。
接收端窗口（rwnd）：最近通知的接收端窗口。
拥塞窗口（cwnd）：一个TCP状态参量，代表着一个TCP允许发送的最大数据量。在任意
一个给定的时刻，TCP不会发送序号大于最大确认序号和cwnd、rwnd中较小者的数据。
初始窗口（iw）：初始窗口是三次握手完成后发送端的拥塞窗口的尺寸。
丢失窗口（lw）：丢失窗口是在一个TCP根据它的重传定时器检测到了数据丢失之后，拥塞窗口的尺寸。
重启窗口（rw）：重启窗口是TCP在一段闲置期之后重新开始传送后拥塞窗口的尺寸（如果使用慢启动算法；参见4.1节以获取更多的讨论）。
传送尺寸：已经被发送但还没有确认的数据的总量。&lt;/p&gt;</description></item><item><title>网络性能排查之TCP重传与重复ACK</title><link>https://www.lucien116.com/archives/149/</link><pubDate>Mon, 10 Oct 2016 08:58:00 +0000</pubDate><guid isPermaLink="false">http://www.lucien116.com/?p=149</guid><description>&lt;p&gt;作为网络管理员，很多时间必然会耗费在修复慢速服务器和其他终端。但用户感到网络运行缓慢并不意味着就是网络问题。&lt;/p&gt;
&lt;p&gt;解决网络性能问题，首先从TCP错误恢复功能（TCP重传与重复ACK）和流控功能说起。之后阐述如何发现网络慢速之源。最后，对网络各组成部分上的数据流进行概况分析。这几张内容将会帮助读者识别，诊断，以及排查慢速网络。&lt;/p&gt;
&lt;p&gt;更多信息
接下来的内容，较多是黑白图片了。虽然看起来有点不爽，但还是很值得一看。&lt;/p&gt;
&lt;p&gt;TCP错误恢复功能：&lt;/p&gt;
&lt;p&gt;TCP的错误恢复功能是定位，诊断及修复网络延时的最佳工具。延时可以在单程也可以往返方向测量。高延时是网络管理员的头号大敌。本节我们讨论TCP高延时是如何导致序列号和确认号乱序的。&lt;/p&gt;
&lt;p&gt;TCP重传：&lt;/p&gt;
&lt;p&gt;主机报文重传是TCP最基本的错误恢复功能，它的目的是防止报文丢失。&lt;/p&gt;
&lt;p&gt;报文丢失的可能因素有很多种，包括应用故障，路由设备过载，或暂时的服务宕机。报文级别速度是很高的，而通常报文丢失是暂时的，因此TCP能够发现和恢复报文丢失显得尤为重要。&lt;/p&gt;
&lt;p&gt;决定报文是否有必要重传的主要机制是重传计时器（retransmission timer），它的主要功能是维护重传超时（RTO）值。当报文使用TCP传输时，重传计时器启动，收到ACK时计时器停止。报文发送至接收到ACK的时间称为往返时间（RTT）。对若干次时间取平均值，该值用于确定最终RTO值。在最终RTO值确定之前，确定每一次报文传输是否有丢包发生使用重传计时器，下图说明了TCP重传过程。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="http://ww3.sinaimg.cn/mw690/7cc829d3gw1ehh4x5m289j20f9097mxw.jpg"&gt;&lt;/p&gt;
&lt;p&gt;当报文发送之后，但接收方尚未发送TCP ACK报文，发送方假设源报文丢失并将其重传。重传之后，RTO值加倍；如果在2倍RTO值到达之前还是没有收到ACK报文，就再次重传。如果仍然没有收到ACK，那么RTO值再次加倍。如此持续下去，每次重传RTO都翻倍，直到收到ACK报文或发送方达到配置的最大重传次数。&lt;/p&gt;
&lt;p&gt;最大重传次数取决于发送操作系统的配置值。默认情况下，Windows主机默认重传5次。大多数Linux系统默认最大15次。两种操作系统都可配置。
示例如下图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="http://ww3.sinaimg.cn/large/7cc829d3gw1ehh4x6lx7ej20il0a4jtq.jpg"&gt;&lt;img loading="lazy" src="http://ww3.sinaimg.cn/mw690/7cc829d3gw1ehh4x80g1oj20im0dj75u.jpg"&gt;&lt;/p&gt;
&lt;p&gt;TCP重传过程发送的第一个报文如下图所示（图片不很清楚，已经尽力了）：
&lt;img loading="lazy" src="http://ww4.sinaimg.cn/large/7cc829d3gw1ehh4x99hacj20i908d74s.jpg"&gt;&lt;/p&gt;
&lt;p&gt;这是一个TCP PSH/ACK报文①，包含648字节数据②，从10.3.30.1发送至10.3.71.7。这是一个典型的数据报文。&lt;/p&gt;
&lt;p&gt;在通常情况下，第一个报文发送之后很快会收到TCP ACK报文。然而，在这个case里，第二个是重传报文。可以在Packet list面板里看到。Info栏清楚的标明“TCP Retransmission”，报文以黑色背景红色字体标出。下图是Packet List面板中的重传示例（仍然不清楚，但可参见上图）：
&lt;img loading="lazy" src="http://ww2.sinaimg.cn/large/7cc829d3gw1ehh4xa9lyej20ih01s0sr.jpg"&gt;&lt;/p&gt;
&lt;p&gt;也可以在Packet Details和Packet Bytes面板中查看来确定是否是重传报文，如下图所示：
&lt;img loading="lazy" src="http://ww4.sinaimg.cn/large/7cc829d3gw1ehh4xauzi4j20i509674x.jpg"&gt;&lt;/p&gt;
&lt;p&gt;注意此报文与源报文相同（除了IP标识和checksum字段）。要验证这一点，比较两个报文的Packet Bytes①。&lt;/p&gt;
&lt;p&gt;在Packet Details面板，注意到重传报文在SEQ/ACK Analysis下面有些额外的信息②。这些信息是由Wireshark提供的而并非报文本身。SEQ/ACK Analysis告诉我们这确实是一个重传报文，RTO值是0.206秒，此时的RTO是基于报文1的时间增量。&lt;/p&gt;
&lt;p&gt;检查剩下的报文会得到类似的结果，不同之处只有IP标识和checksum，以及RTO值。要使报文之间的时间间隔形象化，在Packet List面板中查看Time栏，如下图所示。这里可以看到RTO值的翻倍增长关系。
&lt;img loading="lazy" src="http://ww2.sinaimg.cn/mw690/7cc829d3gw1ehh4xbao53j203q03dt8n.jpg"&gt;&lt;/p&gt;
&lt;p&gt;TCP重复ACK以及快速重传：&lt;/p&gt;
&lt;p&gt;重复ACK是指在接收方收到乱序报文时，所发出的一类TCP报文。TCP使用报文头的序列号和确认号以有效保证数据按照发送的顺序接收和重组。&lt;/p&gt;
&lt;p&gt;当TCP连接建立以后，握手过程中交换的一个最重要的信息是初始序列号（ISN）。一旦连接双方设定了ISN之后，接下来发送的报文所包含的序列号增加一个数据载荷值。&lt;/p&gt;
&lt;p&gt;假设有个主机ISN是5000，发送500字节报文至接收方。一旦报文接收之后，接收端回复一个ACK号为5500的TCP ACK报文，基于以下公式：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sequence Number In + Bytes of Data Received = Acknowledgment Number Out&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;按照上述计算结果，返回发送端的确认编号实际上是接收端希望收到的序列号。示例如下图：
&lt;img loading="lazy" src="http://ww2.sinaimg.cn/mw690/7cc829d3gw1ehh4xbsfecj20f906vjs0.jpg"&gt;
数据接收方通过序列号来检查报文丢失。接收方通过追踪接收到的序列号，能够确认序列号是否乱序。当接收方收到一个不正常的序列号，它会假设传输过程中有报文丢失。为了正确重传数据，接收方必须拥有丢失报文，所以它发送包含有丢失报文正确序列号的ACK报文，以便发送方重传此报文。&lt;/p&gt;
&lt;p&gt;当重传主机从发送端接收到3个重复ACK时，它会假设此报文确实在传送中丢失，并且立即发送一个快速重传。一旦触发了快速重传，所有正在传输的其他报文都被放入队列中，直到快速重传报文发送为止。过程如下图所示：
&lt;img loading="lazy" src="http://ww1.sinaimg.cn/mw690/7cc829d3gw1ehh4xcglmij20f909j756.jpg"&gt;&lt;/p&gt;
&lt;p&gt;承接上文的彩图：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="http://ww3.sinaimg.cn/large/7cc829d3gw1ehh4xd6zucj20im0bo0ub.jpg"&gt;&lt;/p&gt;
&lt;p&gt;本例中第一个报文如下图：
&lt;img loading="lazy" src="http://ww2.sinaimg.cn/mw690/7cc829d3gw1ehh4xds6mwj20if06iq3b.jpg"&gt;
这是一个TCP ACK报文，从数据接收端（172.31.136.85）发给发送端（195.81.202.68）①，确认前一个报文所发送的数据。
此报文中的确认编号是1310973186②，应当是下一个接收报文的序列号，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="http://ww1.sinaimg.cn/mw690/7cc829d3gw1ehh4xe9kpuj20id07edg9.jpg"&gt;
不幸的是接收端的序列号是1310984130①，并不是所期望的值。这意味着报文在传送中丢失。接收端注意到报文乱序，并且在第三个报文中发送重复ACK，如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="http://ww4.sinaimg.cn/mw690/7cc829d3gw1ehh4xflq0yj20i6081jrt.jpg"&gt;&lt;/p&gt;
&lt;p&gt;可以通过以下两种方式之一来确认这是一个重复ACK：&lt;/p&gt;
&lt;p&gt;在Packet Detaisl面板中的Info栏。报文呈现黑色背景红色字体。&lt;/p&gt;
&lt;p&gt;SEQ/ACK Analysis下的Packet Deatails面板。扩展这一栏会发现报文显示为duplicate ACK。接下来几个报文重复此过程。如下图所示：
&lt;img loading="lazy" src="http://ww3.sinaimg.cn/mw690/7cc829d3gw1ehh4xg7iijj20il0263yn.jpg"&gt;
此文件中的第四个报文是发送端所发出具有错误序列号①的另一个数据块。因此，接收端发送第二个重复ACK②。接收端又收到一个乱序报文③。从而触发了第三以及最后一个重复ACK④.&lt;/p&gt;</description></item></channel></rss>