欢迎来到千学网!
您现在的位置:首页 > 实用文 > 合同

软交换网协议解析

时间:2022-10-23 08:36:33 合同 收藏本文 下载本文

下面小编为大家带来软交换网协议解析,本文共14篇,希望大家能够受用!

软交换网协议解析

篇1:软交换网协议解析

在交换机的不断学习中,我们知道交换机的重要作用是无法被替代的,那么其中一类则是软交换。对于软交换,我们这里不再赘述,主要讲解一下交换机中关于软交换网协议及标准?人类的通信包括话音?数据?视频与音频组合的多媒体三大内容?一直以来,上述三类通信业务均是分别由不同的通信网来承载和疏通?电话网承载和疏通语音业务?数据网承载和疏通数据业务,多媒体网承载和疏通多媒体业务?

随着社会信息化程度的进一步加深,通信已经成为人们生活和工作中不可缺少的工具,人们对通信要求也不再仅仅是基本的语音通信业务和简单的WWW浏览和收发E-mail,人们需要的是能够随时?随地?灵活地获取所需要的信息?因此要求电信运营商能够灵活地为用户提供丰富的电信业务,而基于由不同通信网络提供不同业务的运营模式难以满足用户“灵活地获取所需要的信息“的需求,只有构建一个”全业务网络――即能够同时承载和疏通语音?数据?多媒体业务的网络“才能满足用户日益增长的对通信业务的需求?

电话网的历史最为悠久,其核心是电话交换机,电话交换机经历了磁石式?共用电池式?步进制?纵横制?程控制5个发展阶段,其差别在于交换机的实现方式发生了改变?程控制电话交换机的出现是一个历史性的变革,它采用了先进的体系结构,其功能可以分为呼叫业务接入?路由选择(交换)和呼叫业务控制3部分,其中的交换和呼叫业务控制功能均主要是通过程序软件来实现?但其采用的资源独占的电路交换方式,以及为通信的双方提供的对等的双向64kbit/s固定带宽通道不适于承载突发数据量大?上下行数据流量差异大的数据业务?

数据网的种类繁多,根据其采用的广域网协议不同,可将其分为DDN?X.25?帧中继和IP网,由于IP网具有协议简单?终端设备价格低廉?以及基于IP协议的WWW业务的开展,基于IP协议的Internet呈爆炸式发展,一度成为了数据网的代名词?IP网要求用户终端将用户数据信息均封装在IP包中,IP网的核心设备――路由器仅是完成“尽力而为”的IP包转发的简单工作,它采用资源共享的包交换方式,根据业务量需要动态地占用上下行传输通道,因此IP网实际上仅是一个数据传送网,其本身并不提供任何高层业务控制功能,若在IP网上开放语音业务,必须额外增加电话业务的控制设备?值得一提的是,IP网中传送的IP包能够承载任何用户数据信息,为实现语音?数据?多媒体流等多种信息在一个承载网中传送创造了条件?可见,电话网和数据网均存在一定的先天缺陷?无法通过简单地改造而成为一个“全业务网“,因此,为了能够实现在同一个网络上同时提供语音?数据以及多媒体业务,即通信业务的融合,产生了软交换(softswitch)技术?

核心传送层

核心传送层实际上就是软交换网的承载网络,其作用和功能就是将边缘接入层中的各种媒体网关?控制层中的软交换机?业务应用层中的各种服务器平台等各个软交换网网元连接起来?鉴于IP网能够同时承载语音?数据?视频等多种媒体信息,同时具有协议简单?终端设备对协议的支持性好且价格低廉的优势,因此软交换网选择了IP网作为承载网络?软交换网中各网元之间均是将各种控制信息和业务数据信息封装在IP数据包中,通过核心传送层的IP网进行通信?

软交换网协议及标准

软交换网络中同层网元之间?不同层的网元之间均是通过软交换技术定义的标准协议进行通信的?国际上从事软交换相关标准制定的组织主要是IETF和ITU-T?它们分别从计算机界和电信界的立场出发,对软交换协议作出了贡献?

媒体网关与软交换机之间的协议

除SG外的各媒体网关与软交换机之间的协议有MGCP协议和MEGACO/H.248协议两种?MGCP协议是在MEGACO/H.248之前的一个版本,它的灵活性和扩展性比不上MEGACO/H.248,同时在对多运营商的支持方面也不如MEGACO/H.248协议?

MEGACO/H.248实际上是同一个协议的名字,由IETF和ITU联合开发,IETF称为MEGACO,ITU-T称为H.248?MEGACO/H.248称为媒体网关控制协议,它具有协议简单,功能强大,且扩展性很好的特点?SG与软交换机之间采用SIGTRAN协议,SIGTRAN的低层采用SCTP协议,为七号信令在TCP/IP网上传送提供可靠的连接;高层分为M2PA?M2UA?M3UA?由于M3UA具有较大的灵活性,因此目前应用较为广泛?SIGTRAN/SCTP协议的根本功能在于将PSTN中基于TDM的七号信令通过SG以IP网作为承载透传至软交换机,由软交换机完成对七号信令的处理?

软交换机之间的协议

在软交换网协议中有一类情况,就是当需要由不同的软交换机控制的媒体网关进行通信时,相关的软交换机之间需要通信,软交换机与软交换机之间的协议有BICC协议和SIP-T协议两种?BICC协议是ITU-T推荐的标准协议,它主要是将原七号信令中的ISUP协议进行封装,对多媒体数据业务的支持存在一定不足?SIP-T是IETF推荐的标准协议,它主要是对原SIP协议进行扩展,属于一种应用层协议,采用Client-Serve结构,对多媒体数据业务的支持较好?便于增加新业务,同时SIP-T具有简单灵活?易于实现?扩展性好的特点?目前BICC和SIP协议在国际上均有较多的应用?

篇2:香温玉软词语解析

xiāng wēn yù ruǎn

【成语释义】

形容美女的肌肤的'娇嫩温香。代指美女

【成语出处】

明·王玉峰《焚香记·设媒》:“吾家富比陶朱,独没个翠倚红偎。想香温玉软,凤枕鸳帏。”

【感情色彩】

中性

【成语结构】

联合式成语

【成语用法】

作宾语、定语;指美女

【产生年代】

古代成语

【近义词】

香肌玉体 香娇玉嫩

百科

【词目】香温玉软 【读音】xiāng wēn yù ruǎn 【释义】形容年轻女子肌肤的娇嫩温香。也代指美女。 【出处】明·王玉峰《焚香记》第六出:“吾家富比陶朱,独没个翠倚红偎,想香温玉软,凤枕鸳帏。” 【示例】清·褚人获《隋唐演义》第三十一回:“就叫冶儿近身,用手在他身上一摸,却又香温玉软,柔媚可怜,就像连剑也拿不动的。”

篇3:NFS协议的版本解析

对于网络协议来说,随着网络的不断扩展和发展,也跟进着新的版本,那么对于NFS协议来说都有哪些版本呢?下面我们就来详细分析一下,具体的NFS协议版本都有哪些。来看看各NFS协议版本的主要区别。

V3相对V2的主要区别:

1、文件尺寸

V2最大只支持32BIT的文件大小(4G),而NFS协议的V3新增加了支持 64BIT文件大小的技术.

2、文件传输尺寸

V3没有限定传输尺寸,V2最多只能设定为8k,可以使用 -rsize and -wsize 来进行设定.

3、完整的信息返回

V3增加和完善了许多错误和成功信息的返回,对于服务器的设置和管理能带来很大好处.

4、增加了对TCP传输协议的支持

V2只提供了对UDP协议的支持,在一些高要求的网络环境中有很大限制,V3增加了对TCP协议的支持

*5、异步写入特性

6、改进了SERVER的mount性能

7、有更好的 I/O WRITES 性能.

9、更强网络运行效能,使得网络运作更为有效.

10、更强的灾难恢复功能.

异步写入特性(v3新增加)介绍:

NFS协议的V3版本能否使用异步写入,这是可选择的一种特性.NFS V3客户端发发送一个异步写入请求到服务器,在给客户端答复之前服务器并不是必须要将数据写入到存储器中(稳定的).服务器能确定何时去写入数据或者将多个写入请求聚合到一起并加以处理,然后写入.客户端能保持一个数据的copy以防万一服务器不能完整的将数据写入.当客户端希望释放这个copy的时候,它会向服务器通过这个操作过程,以确保每个操作步骤的完整.异步写入能够使服务器去确定最好的同步数据的策略.使数据能尽可能的同步的提交何到达.与V2比较来看,这样的机制能更好的实现数据缓冲和更多的平行(平衡).而NFS V2的SERVER在将数据写入存储器之前不能再相应任何的写入请求.

V4相对V3的改进:

1:改进了INTERNET上的存取和执行效能

2:在协议中增强了安全方面的特性

3:增强的跨平台特性

篇4:TCP协议疑难杂症全景解析

TCP协议疑难杂症全景解析

说明:

1).本文以TCP的发展历程解析容易引起混淆,误会的方方面面

2).本文不会贴大量的源码,大多数是以文字形式描述,我相信文字看起来是要比代码更轻松的

3).针对对象:对TCP已经有了全面了解的人,因为本文不会解析TCP头里面的每一个字段或者3次握手的细节,也不会解释慢启动和快速重传的定义

4).除了《TCP/IP详解》(卷一,卷二)以及《Unix网络编程》以及Linux源代码之外,学习网络更好的资源是RFC

5).本文给出一个提纲,如果想了解细节,请直接查阅RFC

6).翻来覆去,终于找到了这篇备忘,本文基于这篇备忘文档修改。

1.网络协议设计

ISO提出了OSI分层网络模型,这种分层模型是理论上的,TCP/IP最终实现了一个分层的协议模型,每一个层次对应一组网络协议完成一组特定的功能,该组网络协议被其下的层次复用和解复用。这就是分层模型的本质,最终所有的逻辑被编码到线缆或者电磁波。

分层模型是很好理解的,然而对于每一层的协议设计却不是那么容易。TCP/IP的漂亮之处在于:协议越往上层越复杂。我们把网络定义为互相连接在一起的设备,网络的本质作用还是“端到端”的通信,然而希望互相通信的设备并不一定要“直接”连接在一起,因此必然需要一些中间的设备负责转发数据,因此就把连接这些中间设备的线缆上跑的协议定义为链路层协议,实际上所谓链路其实就是始发与一个设备,通过一根线,终止于另一个设备。我们把一条链路称为“一跳”。因此一个端到端的网络包含了“很多跳”。

2.TCP和IP协议

终止于IP协议,我们已经可以完成一个端到端的通信,为何还需要TCP协议?这是一个问题,理解了这个问题,我们就能理解TCP协议为何成了现在这个样子,为何如此“复杂”,为何又如此简单。

正如其名字所展示的那样,TCP的作用是传输控制,也就是控制端到端的传输,那为何这种控制不在IP协议中实现的。答案很简单,那就是这会增加IP协议的复杂性,而IP协议需要的就是简单。这是什么原因造成的呢?

首先我们认识一下为何IP协议是沙漏的细腰部分。它的下层是繁多的链路层协议,这些链路提供了相互截然不同且相差很远的语义,为了互联这些异构的网络,我们需要一个网络层协议起码要提供一些适配的功能,另外它必然不能提供太多的“保证性服务”,因为上层的保证性依赖下层的约束性更强的保证性,你永远无法在一个100M吞吐量的链路之上实现的IP协议保证1000M的吞吐量...

IP协议设计为分组转发协议,每一跳都要经过一个中间节点,路由的设计是TCP/IP网络的另一大创举,这样,IP协议就无需方向性,路由信息和协议本身不再强关联,它们仅仅通过IP地址来关联,因此,IP协议更加简单。路由器作为中间节点也不能太复杂,这涉及到成本问题,因此路由器只负责选路以及转发数据包。

因此传输控制协议必然需要在端点实现。在我们详谈TCP协议之前,首先要看一下它不能做什么,由于IP协议不提供保证,TCP也不能提供依赖于IP下层链路的这种保证,比如带宽,比如时延,这些都是链路层决定的,既然IP协议无法修补,TCP也不能,然而它却能修正始于IP层的一些“不可保证性质”,这些性质包括IP层的不可靠,IP层的不按顺序,IP层的无方向/无连接。

将该小节总结一下,TCP/IP模型从下往上,功能增加,需要实现的设备减少,然而设备的复杂性却在增加,这样保证了成本的最小化,至于性能或者因素,靠软件来调节吧,TCP协议就是这样的软件,实际上最开始的时候,TCP并不考虑性能,效率,公平性,正是考虑了这些,TCP协议才复杂了起来。

3.TCP协议

这是一个纯软件协议,为何将其设计上两个端点,参见上一小节,本节详述TCP协议,中间也穿插一些简短的论述。

3.1.TCP协议

确切的说,TCP协议有两重身份,作为网络协议,它弥补了IP协议尽力而为服务的不足,实现了有连接,可靠传输,报文按序到达。作为一个主机软件,它和UDP以及左右的传输层协议隔离了主机服务和网络,它们可以被看做是一个多路复用/解复用器,将诸多的主机进程数据复用/解复用到IP层。可以看出,不管从哪个角度,TCP都作为一个接口存在,作为网络协议,它和对端的TCP接口,实现TCP的控制逻辑,作为多路复用/解复用器,它和下层IP协议接口,实现协议栈的功能,而这正是分层网络协议模型的基本定义(两类接口,一类和下层接口,另一类和对等层接口)。

我们习惯于将TCP作为协议栈的最顶端,而不把应用层协议当成协议栈的一部分,这部分是因为应用层被TCP/UDP解复用了之后,呈现出了一种太复杂的局面,应用层协议用一种不同截然不同的方式被解释,应用层协议习惯于用类似ASN.1标准来封装,这正体现了TCP协议作为多路复用/解复用器的重要性,由于直接和应用接口,它可以很容易直接被应用控制,实现不同的传输控制策略,这也是TCP被设计到离应用不太远的地方的原因之一。

总之,TCP要点有四,一曰有连接,二曰可靠传输,三曰数据按照到达,四曰端到端流量控制。注意,TCP被设计时只保证这四点,此时它虽然也有些问题,然而很简单,然而更大的问题很快呈现出来,使之不得不考虑和IP网络相关的东西,比如公平性,效率,因此增加了拥塞控制,这样TCP就成了现在这个样子。

3.2.有连接,可靠传输,数据按序到达的TCP

IP协议是没有方向的,数据报传输能到达对端全靠路由,因此它是一跳一跳地到达对端的,只要有一跳没有到达对端的路由,那么数据传输将失败,其实路由也是互联网的核心之一,实际上IP层提供的核心基本功能有两点,第一点是地址管理,第二点就是路由选路。TCP利用了IP路由这个简单的功能,因此TCP不必考虑选路,这又一个它被设计成端到端协议的原因。

既然IP已经能尽力让单独的数据报到达对端,那么TCP就可以在这种尽力而为的网络上实现其它的更加严格的控制功能。TCP给无连接的IP网络通信增加了连接性,确认了已经发送出去的数据的状态,并且保证了数据的顺序。

3.2.1.有连接

这是TCP的基本,因为后续的传输的可靠性以及数据顺序性都依赖于一条连接,这是最简单的实现方式,因此TCP被设计成一种基于流的协议,既然TCP需要事先建立连接,之后传输多少数据就无所谓了,只要是同一连接的数据能识别出来即可。

疑难杂症1:3次握手和4次挥手

TCP使用3次握手建立一条连接,该握手初始化了传输可靠性以及数据顺序性必要的信息,这些信息包括两个方向的初始序列号,确认号由初始序列号生成,使用3次握手是因为3次握手已经准备好了传输可靠性以及数据顺序性所必要的信息,该握手的第3次实际上并不是需要单独传输的,完全可以和数据一起传输。

TCP使用4次挥手拆除一条连接,为何需要4次呢?因为TCP是一个全双工协议,必须单独拆除每一条信道。注意,4次挥手和3次握手的意义是不同的,很多人都会问为何建立连接是3次握手,而拆除连接是4次挥手。3次握手的目的很简单,就是分配资源,初始化序列号,这时还不涉及数据传输,3次就足够做到这个了,而4次挥手的目的是终止数据传输,并回收资源,此时两个端点两个方向的序列号已经没有了任何关系,必须等待两方向都没有数据传输时才能拆除虚链路,不像初始化时那么简单,发现SYN标志就初始化一个序列号并确认SYN的序列号。因此必须单独分别在一个方向上终止该方向的数据传输。

疑难杂症2:TIME_WAIT状态

为何要有这个状态,原因很简单,那就是每次建立连接的时候序列号都是随机产生的,并且这个序列号是32位的,会回绕。现在我来解释这和TIME_WAIT有什么关系。

任何的TCP分段都要在尽力而为的IP网络上传输,中间的路由器可能会随意的缓存任何的IP数据报,它并不管这个IP数据报上被承载的是什么数据,然而根据经验和互联网的大小,一个IP数据报最多存活MSL(这是根据地球表面积,电磁波在各种介质中的传输速率以及IP协议的TTL等综合推算出来的,如果在火星上,这个MSL会大得多...)。

现在我们考虑终止连接时的被动方发送了一个FIN,然后主动方回复了一个ACK,然而这个ACK可能会丢失,这会造成被动方重发FIN,这个FIN可能会在互联网上存活MSL。

如果没有TIME_WAIT的话,假设连接1已经断开,然而其被动方最后重发的那个FIN(或者FIN之前发送的任何TCP分段)还在网络上,然而连接2重用了连接1的所有的5元素(源IP,目的IP,TCP,源端口,目的端口),刚刚将建立好连接,连接1迟到的FIN到达了,这个FIN将以比较低但是确实可能的概率终止掉连接2.

为何说是概率比较低呢?这涉及到一个匹配问题,迟到的FIN分段的序列号必须落在连接2的一方的期望序列号范围之内。虽然这种巧合很少发生,但确实会发生,毕竟初始序列号是随机产生了。因此终止连接的主动方必须在接受了被动方且回复了ACK之后等待2*MSL时间才能进入CLOSE状态,之所以乘以2是因为这是保守的算法,最坏情况下,针对被动方的ACK在以最长路线(经历一个MSL)经过互联网马上到达被动方时丢失。

为了应对这个问题,RFC793对初始序列号的生成有个建议,那就是设定一个基准,在这个基准之上搞随机,这个基准就是时间,我们知道时间是单调递增的。然而这仍然有问题,那就是回绕问题,如果发生回绕,那么新的序列号将会落到一个很低的值。因此最好的办法就是避开“重叠”,其含义就是基准之上的随机要设定一个范围。

要知道,很多人很不喜欢看到服务器上出现大量的TIME_WAIT状态的连接,因此他们将TIME_WAIT的值设置的很低,这虽然在大多数情况下可行,然而确实也是一种冒险行为。最好的方式就是,不要重用一个连接。

疑难杂症3:重用一个连接和重用一个套接字

这是根本不同的,单独重用一个套接字一般不会有任何问题,因为TCP是基于连接的。比如在服务器端出现了一个TIME_WAIT连接,那么该连接标识了一个五元素,只要客户端不使用相同的源端口,连接服务器是没有问题的,因为迟到的FIN永远不会到达这个连接。记住,一个五元素标识了一个连接,而不是一个套接字(当然,对于BSD套接字而言,服务端的accept套接字确实标识了一个连接)。

3.2.2.传输可靠性

基本上传输可靠性是靠确认号实现的,也就是说,每发送一个分段,接下来接收端必然要发送一个确认,发送端收到确认后才可以发送下一个字节。这个原则最简单不过了,教科书上的“停止-等待”协议就是这个原则的字节版本,只是TCP使用了滑动窗口机制使得每次不一定发送一个字节,但是这是后话,本节仅仅谈一下确认的超时机制。

怎么知道数据到达对端呢?那就是对端发送一个确认,但是如果一直收不到对端的确认,发送端等多久呢?如果一直等下去,那么将无法发现数据的丢失,协议将不可用,如果等待时间过短,可能确认还在路上,因此等待时间是个问题,另外如何去管理这个超时时间也是一个问题。

疑难杂症4:超时时间的计算

绝对不能随意去揣测超时的时间,而应该给出一个精确的算法去计算。毫无疑问,一个TCP分段的回复到达的时间就是一个数据报往返的时间,因此标准定义了一个新的名词RTT,代表一个TCP分段的往返时间。然而我们知道,IP网络是尽力而为的,并且路由是动态的,且路由器会毫无先兆的缓存或者丢弃任何的数据报,因此这个RTT是需要动态测量的,也就是说起码每隔一段时间就要测量一次,如果每次都一样,万事大吉,然而世界并非如你所愿,因此我们需要找到的恰恰的一个“平均值”,而不是一个准确值。

这个平均值如果仅仅直接通过计算多次测量值取算术平均,那是不恰当的,因为对于数据传输延时,我们必须考虑的路径延迟的瞬间抖动,否则如果两次测量值分别为2和98,那么超时值将是50,这个值对于2而言,太大了,结果造成了数据的延迟过大(本该重传的等待了好久才重传),然而对于98而言,太小了,结果造成了过度重传(路途遥远,本该很慢,结果大量重传已经正确确认但是迟到的TCP分段)。

因此,除了考虑每两次测量值的偏差之外,其变化率也应该考虑在内,如果变化率过大,则通过以变化率为自变量的函数为主计算RTT(如果陡然增大,则取值为比较大的正数,如果陡然减小,则取值为比较小的负数,然后和平均值加权求和),反之如果变化率很小,则取测量平均值。这是不言而喻的,这个算法至今仍然工作的很好。

疑难杂症5:超时计时器的管理-每连接单一计时器

很显然,对每一个TCP分段都生成一个计时器是最直接的方式,每个计时器在RTT时间后到期,如果没有收到确认,则重传。然而这只是理论上的合理,对于大多数操作系统而言,这将带来巨大的内存开销和调度开销,因此采取每一个TCP连接单一计时器的设计则成了一个默认的选择。可是单一的计时器怎么管理如此多的发出去的TCP分段呢?又该如何来设计单一的计时器呢。

设计单一计时器有两个原则:1.每一个报文在长期收不到确认都必须可以超时;2.这个长期收不到中长期不能和测量的RTT相隔太远。因此RFC2988定义一套很简单的原则:

a.发送TCP分段时,如果还没有重传定时器开启,那么开启它。

b.发送TCP分段时,如果已经有重传定时器开启,不再开启它。

c.收到一个非冗余ACK时,如果有数据在传输中,重新开启重传定时器。

d.收到一个非冗余ACK时,如果没有数据在传输中,则关闭重传定时器。

我们看看这4条规则是如何做到以上两点的,根据a和c(在c中,注意到ACK是非冗余的),任何TCP分段只要不被确认,超时定时器总会超时的。然而为何需要c呢?只有规则a存在的话,也可以做到原则1。实际上确实是这样的,但是为了不会出现过早重传,才添加了规则c,如果没有规则c,那么万一在重传定时器到期前,发送了一些数据,这样在定时器到期后,除了很早发送的数据能收到ACK外,其它稍晚些发送的数据的ACK都将不会到来,因此这些数据都将被重传。有了规则c之后,只要有分段ACK到来,则重置重传定时器,这很合理,因此大多数正常情况下,从数据的发出到ACK的到来这段时间以及计算得到的RTT以及重传定时器超时的时间这三者相差并不大,一个ACK到来后重置定时器可以保护后发的数据不被过早重传。

这里面还有一些细节需要说明。一个ACK到来了,说明后续的ACK很可能会依次到来,也就是说丢失的可能性并不大,另外,即使真的有后发的TCP分段丢失现象发生,也会在最多2倍定时器超时时间的范围内被重传(假设该报文是第一个报文发出启动定时器之后马上发出的,丢失了,第一个报文的ACK到来后又重启了定时器,又经过了一个超时时间才会被重传)。虽然这里还没有涉及拥塞控制,但是可见网络拥塞会引起丢包,丢包会引起重传,过度重传反过来加重网络拥塞,设置规则c的结果可以缓解过多的重传,毕竟将启动定时器之后发送的数据的重传超时时间拉长了最多一倍左右。最多一倍左右的超时偏差做到了原则2,即“这个长期收不到中长期不能和测量的RTT相隔太远”。

还有一点,如果是一个发送序列的最后一个分段丢失了,后面就不会收到冗余ACK,这样就只能等到超时了,并且超时时间几乎是肯定会比定时器超时时间更长。如果这个分段是在发送序列的靠后的时间发送的且和前面的发送时间相隔时间较远,则其超时时间不会很大,反之就会比较大。

疑难杂症6:何时测量RTT

目前很多TCP实现了时间戳,这样就方便多了,发送端再也不需要保存发送分段的时间了,只需要将其放入协议头的时间戳字段,然后接收端将其回显在ACK即可,然后发送端收到ACK后,取出时间戳,和当前时间做算术差,即可完成一次RTT的测量。

3.2.3.数据顺序性

基本上传输可靠性是靠序列号实现的。

疑难杂症7:确认号和超时重传

确认号是一个很诡异的东西,因为TCP的发送端对于发送出去的一个数据序列,它只要收到一个确认号就认为确认号前面的数据都被收到了,即使前面的某个确认号丢失了,也就是说,发送端只认最后一个确认号。这是合理的,因为确认号是接收端发出的,接收端只确认按序到达的最后一个TCP分段。

另外,发送端重发了一个TCP报文并且接收到该TCP分段的确认号,并不能说明这个重发的报文被接收了,也可能是数据早就被接收了,只是由于其ACK丢失或者其ACK延迟到达导致了超时。值得说明的是,接收端会丢弃任何重复的数据,即使丢弃了重复的数据,其ACK还是会照发不误的。

标准的早期TCP实现为,只要一个TCP分段丢失,即使后面的TCP分段都被完整收到,发送端还是会重传从丢失分段开始的所有报文,这就会导致一个问题,那就是重传风暴,一个分段丢失,引起大量的重传。这种风暴实则不必要的,因为大多数的TCP实现中,接收端已经缓存了乱序的分段,这些被重传的丢失分段之后的分段到达接收端之后,很大的可能性是被丢弃。关于这一点在拥塞控制被引入之后还会提及(问题先述为快:本来报文丢失导致超时就说明网络很可能已然拥塞,重传风暴只能加重其拥塞程度)。

疑难杂症8:乱序数据缓存以及选择确认

TCP是保证数据顺序的,但是并不意味着它总是会丢弃乱序的TCP分段,具体会不会丢弃是和具体实现相关的,RFC建议如果内存允许,还是要缓存这些乱序到来的分段,然后实现一种机制等到可以拼接成一个按序序列的时候将缓存的分段拼接,这就类似于IP协议中的分片一样,但是由于IP数据报是不确认的,因此IP协议的实现必须缓存收到的任何分片而不能将其丢弃,因为丢弃了一个IP分片,它就再也不会到来了。

现在,TCP实现了一种称为选择确认的方式,接收端会显式告诉发送端需要重传哪些分段而不需要重传哪些分段。这无疑避免了重传风暴。

疑难杂症9:TCP序列号的回绕的问题

TCP的序列号回绕会引起很多的问题,比如序列号为s的分段发出之后,m秒后,序列号比s小的序列号为j的分段发出,只不过此时的j比上一个s多了一圈,这就是回绕问题,那么如果这后一个分段到达接收端,这就会引发彻底乱序-本来j该在s后面,结果反而到达前面了,这种乱序是TCP协议检查不出来的。我们仔细想一下,这种情况确实会发生,数据分段并不是一个字节一个字节发送出去的,如果存在一个速率为1Gbps的网络,TCP发送端1秒会发送125MB的数据,32位的序列号空间能传输2的32次方个字节,也就是说32秒左右就会发生回绕,我们知道这个值远小于MSL值,因此会发生的。

有个细节可能会引起误会,那就是TCP的窗口大小空间是序列号空间的一半,这样恰好在满载情况下,数据能填满发送窗口和接收窗口,序列号空间正好够用。然而事实上,TCP的初始序列号并不是从0开始的,而是随机产生的(当然要辅助一些更精妙的算法),因此如果初始序列号比较接近2的32次方,那么很快就会回绕。

当然,如今可以用时间戳选项来辅助作为序列号的一个识别的部分,接收端遇到回绕的情况,需要比较时间戳,我们知道,时间戳是单调递增的,虽然也会回绕,然而回绕时间却要长很多。这只是一种策略,在此不详谈。还有一个很现实的问题,理论上序列号会回绕,但是实际上,有多少TCP的端点主机直接架设在1G的网络线缆两端并且接收方和发送方的窗口还能恰好被同时填满。另外,就算发生了回绕,也不是一件特别的事情,回绕在计算机里面太常见了,只需要能识别出来即可解决,对于TCP的序列号而言,在高速网络(点对点网络或者以太网)的两端,数据发生乱序的可能性很小,因此当收到一个序列号突然变为0或者终止序列号小于起始序列号的情况后,很容易辨别出来,只需要和前一个确认的分段比较即可,如果在一个经过路由器的网络两端,会引发IP数据报的顺序重排,对于TCP而言,虽然还会发生回绕,也会慢得多,且考虑到拥塞窗口(目前还没有引入)一般不会太大,窗口也很难被填满到65536。

3.2.4.端到端的流量控制

端到端的流量控制使用滑动窗口来实现。滑动窗口的原理非常简单,基本就是一个生产者/消费者模型

疑难杂症10:流量控制的真实意义

很多人以为流量控制会很有效的协调两端的流量匹配,确实是这样,但是如果你考虑到网络的利用率问题,TCP的流量控制机制就不那么完美了,造成这种局面的原因在于,滑动窗口只是限制了最大发送的数据,却没有限制最小发送的数据,结果导致一些很小的数据被封装成TCP分段,报文协议头所占的比例过于大,造成网络利用率下降,这就引出了接下来的内容,那就是端到端意义的TCP协议效率。

~~~~~~~~~~~~~~~~~~~~

承上启下

终于到了阐述问题的时候了,以上的TCP协议实现的非常简单,这也是TCP的标准实现,然而很快我们就会发现各种各样的问题。这些问题导致了标准化协会对TCP协议进行了大量的修补,这些修补杂糅在一起让人们有些云里雾里,不知所措。本文档就旨在分离这些杂乱的情况,实际上,根据RFC,这些杂乱的情况都是可以找到其单独的发展轨迹的。

~~~~~~~~~~~~~~~~~~~~

4.端到端意义上的TCP协议效率

4.1.三个问题以及解决

问题1描述:接收端处理慢,导致接收窗口被填满

这明显是速率不匹配引发的问题,然而即使速率不匹配,只要滑动窗口能协调好它们的速率就好,要快都快,要慢都慢,事实上滑动窗口在这一点上做的很好。但是如果我们不得不从效率上来考虑问题的话,事实就不那么乐观了。考虑此时接收窗口已然被填满,慢速的应用程序慢腾腾的读取了一个字节,空出一个位置,然后通告给TCP的发送端,发送端得知空出一个位置,马上发出一个字节,又将接收端填满,然后接收应用程序又一次慢腾腾...这就是糊涂窗口综合症,一个大多数人都很熟悉的词。这个问题极大的浪费了网络带宽,降低了网络利用率。好比从大同拉100吨煤到北京需要一辆车,拉1Kg煤到北京也需要一辆车(超级夸张的一个例子,请不要相信),但是一辆车开到北京的开销是一定的...

问题1解决:窗口通告

对于问题1,很显然问题出在接收端,我们没有办法限制发送端不发送小分段,但是却可以限制接收端通告小窗口,这是合理的,这并不影响应用程序,此时经典的延迟/吞吐量反比律将不再适用,因为接收窗口是满的,其空出一半空间表示还有一半空间有数据没有被应用读取,和其空出一个字节的空间的效果是一样的,因此可以限制接收端当窗口为0时,直接通告给发送端以阻止其继续发送数据,只有当其接收窗口再次达到MSS的一半大小的时候才通告一个不为0的窗口,此前对于所有的发送端的窗口probe分段(用于探测接收端窗口大小的probe分段,由TCP标准规定),全部通告窗口为0,这样发送端在收到窗口不为0的通告,那么肯定是一个比较大的窗口,因此发送端可以一次性发出一个很大的TCP分段,包含大量数据,也即拉了好几十吨的煤到北京,而不是只拉了几公斤。

即,限制窗口通告时机,解决糊涂窗口综合症

问题2描述:发送端持续发送小包,导致窗口闲置

这明显是发送端引起的问题,此时接收端的窗口开得很大,然而发送端却不积累数据,还是一味的发送小块数据分段。只要发送了任和的分段,接收端都要无条件接收并且确认,这完全符合TCP规范,因此必然要限制发送端不发送这样的小分段,

问题2解决:Nagle算法

Nagel算法很简单,标准的Nagle算法为:

IF 数据的大小和窗口的大小都超过了MSS

Then 发送数据分段

ELSE

IF 还有发出的TCP分段的确认没有到来

Then 积累数据到发送队列的末尾的TCP分段

ELSE

发送数据分段

EndIF

EndIF

可是后来,这个算法变了,变得更加灵活了,其中的:

IF 还有发出的TCP分段的确认没有到来

变成了

IF 还有发出的不足MSS大小的TCP分段的确认没有到来

这样如果发出了一个MSS大小的分段还没有被确认,后面也是可以随时发送一个小分段的,这个改进降低了算法对延迟时间的影响。这个算法体现了一种自适应的策略,越是确认的快,越是发送的快,虽然Nagle算法看起来在积累数据增加吞吐量的同时也加大的时延,可事实上,如果对于类似交互式的应用,时延并不会增加,因为这类应用回复数据也是很快的,比如Telnet之类的服务必然需要回显字符,因此能和对端进行自适应协调。

注意,Nagle算法是默认开启的,但是却可以关闭。如果在开启的情况下,那么它就严格按照上述的算法来执行。

问题3.确认号(ACK)本身就是不含数据的分段,因此大量的确认号消耗了大量的带宽

这是TCP为了确保可靠性传输的规范,然而大多数情况下,ACK还是可以和数据一起捎带传输的。如果没有捎带传输,那么就只能单独回来一个ACK,如果这样的分段太多,网络的利用率就会下降。从大同用火车拉到北京100吨煤,为了确认煤已收到,北京需要派一辆同样的火车空载开到大同去复命,因为没有别的交通工具,只有火车。如果这位复命者刚开着一列火车走,又从大同来了一车煤,这拉煤的哥们儿又要开一列空车去复命了。

问题3的解决:

RFC建议了一种延迟的ACK,也就是说,ACK在收到数据后并不马上回复,而是延迟一段可以接受的时间,延迟一段时间的目的是看能不能和接收方要发给发送方的数据一起回去,因为TCP协议头中总是包含确认号的,如果能的话,就将ACK一起捎带回去,这样网络利用率就提高了。往大同复命的确认者不必开一辆空载火车回大同了,此时北京正好有一批货物要送往大同,这位复命者搭着这批货的火车返回大同。

如果等了一段可以接受的时间,还是没有数据要发往发送端,此时就需要单独发送一个ACK了,然而即使如此,这个延迟的ACK虽然没有等到可以被捎带的数据分段,也可能等到了后续到来的TCP分段,这样它们就可以取最大者一起返回了,要知道,TCP的确认号是收到的按序报文的最后一个字节的后一个字节。最后,RFC建议,延迟的ACK最多等待两个分段的积累确认。

4.2.分析三个问题之间的关联

三个问题导致的结果是相同的,但是要知道它们的原因本质上是不同的,问题1几乎总是出现在接收端窗口满的情况下,而问题2几乎总是发生在窗口闲置的情况下,问题3看起来是最无聊的,然而由于TCP的要求,必须要有确认号,而且一个确认号就需要一个TCP分段,这个分段不含数据,无疑是很小的。

三个问题都导致了网络利用率的降低。虽然两个问题导致了同样的结果,但是必须认识到它们是不同的问题,很自然的将这些问题的解决方案汇总在一起,形成一个全局的解决方案,这就是如今的操作系统中的解决方案。

4.3.问题的杂糅情况

疑难杂症11:糊涂窗口解决方案和Nagle算法

糊涂窗口综合症患者希望发送端积累TCP分段,而Nagle算法确实保证了一定的TCP分段在发送端的积累,另外在延迟ACK的延迟的那一会时间,发送端会利用这段时间积累数据。然而这却是三个不同的问题。Nagle算法可以缓解糊涂窗口综合症,却不是治本的良药。

疑难杂症12:Nagle算法和延迟ACK

延迟ACK会延长ACK到达发送端的时间,由于标准Nagle算法只允许一个未被确认的TCP分段,那无疑在接收端,这个延迟的ACK是毫无希望等待后续数据到来最终进行积累确认的,如果没有数据可以捎带这个ACK,那么这个ACK只有在延迟确认定时器超时的时候才会发出,这样在等待这个ACK的过程中,发送端又积累了一些数据,因此延迟ACK实际上是在增加延迟的代价下加强了Nagle算法。在延迟ACK加Nagle算法的情况下,接收端只有不断有数据要发回,才能同时既保证了发送端的分段积累,又保证了延迟不增加,同时还没有或者很少有空载的ACK。

要知道,延迟ACK和Nagle是两个问题的解决方案。

疑难杂症13:到底何时可以发送数据

到底何时才能发送数据呢?如果单从Nagle算法上看,很简单,然而事实证明,情况还要更复杂些。如果发送端已经排列了3个TCP分段,分段1,分段2,分段3依次被排入,三个分段都是小分段(不符合Nagle算法中立即发送的标准),此时已经有一个分段被发出了,且其确认还没有到来,请问此时能发送分段1和2吗?如果按照Nagle算法,是不能发送的,但实际上它们是可以发送的,因为这两个分段已经没有任何机会再积累新的数据了,新的数据肯定都积累在分段3上了。问题在于,分段还没有积累到一定大小时,怎么还可以产生新的分段?这是可能的,但这是另一个问题,在此不谈。

Linux的TCP实现在这个问题上表现的更加灵活,它是这么判断能否发送的(在开启了Nagle的情况下):

IF (没有超过拥塞窗口大小的数据分段未确认 || 数据分段中包含FIN ) &&

数据分段没有超越窗口边界

Then

IF 分段在中间(上述例子中的分段1和2) ||

分段是紧急模式      ||

通过上述的Nagle算法(改进后的Nagle算法)

Then 发送分段

EndIF

EndIF

曾经我也改过Nagle算法,确切的说不是修改Nagle算法,而是修改了“到底何时能发送数据”的策略,以往都是发送端判断能否发送数据的,可是如果此时有延迟ACK在等待被捎带,而待发送的数据又由于积累不够或者其它原因不能发送,因此两边都在等,这其实在某些情况下不是很好。我所做的改进中对待何时能发送数据又增加了一种情况,这就是“ACK拉”的情况,一旦有延迟ACK等待发送,判断一下有没有数据也在等待发送,如果有的话,看看数据是否大到了一定程度,在此,我选择的是MSS的一半:

IF (没有超过拥塞窗口大小的数据分段未确认 || 数据分段中包含FIN ) &&

数据分段没有超越窗口边界

Then

IF 分段在中间(上述例子中的分段1和2) ||

分段是紧急模式      ||

通过上述的Nagle算法(改进后的Nagle算法)

Then 发送分段

EndIF

ELSE IF 有延迟ACK等待传输        &&

发送队列中有待发送的TCP分段   &&

发送队列的头分段大小大于MSS的一半

Then 发送队列头分段且捎带延迟ACK

EndIF

另外,发送队列头分段的大小是可以在统计意义上动态计算的,也不一定非要是MSS大小的一半。我们发现,这种算法对于交互式网路应用是自适应的,你打字越快,特定时间内积累的分段就越长,对端回复的越快(可以捎带ACK),本端发送的也就越快(以Echo举例会更好理解)。

疑难杂症14:《TCP/IP详解(卷一)》中Nagle算法的例子解读

这个问题在网上搜了很多的答案,有的说RFC的建议,有的说别的。可是实际上这就是一个典型的“竞态问题”:

首先服务器发了两个分段:

数据段12:ack 14

数据段13:ack 14,54:56

然后客户端发了两个分段:

数据段14:ack 54,14:17

数据段15:ack 56,17:18

可以看到数据段14本来应该确认56的,但是确认的却是54。也就是说,数据段已经移出队列将要发送但还未发送的时候,数据段13才到来,软中断处理程序抢占了数据段14的发送进程,要知道此时只是把数据段14移出了队列,还没有更新任何的状态信息,比如“发出但未被确认的分段数量”,此时软中断处理程序顺利接收了分段13,然后更新窗口信息,并且检查看有没有数据要发送,由于分段14已经移出队列,下一个接受发送检查的就是分段15了,由于状态信息还没有更新,因此分段15顺利通过发送检测,发送完成。

可以看Linux的源代码了解相关信息,tcp_write_xmit这个函数在两个地方会被调用,一个是TCP的发送进程中,另一个就是软中断的接收处理中,两者在调用中的竞态就会引起《详解》中的那种情况。注意,这种不加锁的发送方式是合理的,也是最高效的,因此TCP的处理语义会做出判断,丢弃一切不该接收或者重复接收的分段的。

~~~~~~~~~~~~~~~~~~~~

承上启下

又到了该承上启下,到此为止,我们叙述的TCP还都是简单的TCP,就算是简单的TCP,也存在上述的诸多问题,就更别提继续增加TCP的复杂性了。到此为止,我们的TCP都是端到端意义上的,然而实际上TCP要跑在IP网络之上的,而IP网络的问题是很多的,是一个很拥堵网络。不幸的是,TCP的有些关于确认和可靠性的机制还会加重IP网络的拥堵。

~~~~~~~~~~~~~~~~~~~~

5.IP网络之上的TCP

5.1.端到端的TCP协议和IP协议之间的矛盾

端到端的TCP只能看到两个节点,那就是自己和对方,它们是看不到任何中间的路径的。可是IP网络却是一跳一跳的,它们的矛盾之处在于TCP的端到端流量控制必然会导致网络拥堵。因为每条TCP连接的一端只知道它对端还有多少空间用于接收数据,它们并不管到达对端的路径上是否还有这么大的容量,事实上所有连接的这些空间加在一起将瞬间超过IP网络的容量,因此TCP也不可能按照滑动窗口流量控制机制很理想的运行。

势必需要一种拥塞控制机制,反应路径的拥塞情况。

疑难杂症15:拥塞控制的本质

由于TCP是端到端协议,因此两端之间的控制范畴属于流量控制,IP网络的拥塞会导致TCP分段的丢失,由于TCP看不到中间的路由器,因此这种丢失只会发生中间路由器,当然两个端点的网卡或者IP层丢掉数据分段也是TCP看不到的。因此拥塞控制必然作用于IP链路。事实上我们可以得知,只有在以下情况下拥塞控制才会起作用:

a.两个或两个以上的连接(其中一个一定要是TCP,另一个可以是任意连接)经过同一个路由器或者同一个链路时;

b.只有一个TCP连接,然而它经过了一个路由器时。

其它情况下是不会拥塞的。因为一个TCP总是希望独享整条网络通路,而这对于多个连接而言是不可能的,必须保证TCP的公平性,这样这种拥塞控制机制才合理。本质上,拥塞的原因就是大家都想独享全部带宽资源,结果导致拥塞,这也是合理的,毕竟TCP看不到网络的状态,同时这也决定了TCP的拥塞控制必须采用试探性的方式,最终到达一个足以引起其“反应”的“刺激点”。

拥塞控制需要完成以下两个任务:1.公平性;2.拥塞之后退出拥塞状态。

疑难杂症16:影响拥塞的因素

我们必须认识到拥塞控制是一个整体的机制,它不偏向于任何TCP连接,因此这个机制内在的就包含了公平性。那么影响拥塞的因素都有什么呢?具有讽刺意味的是,起初TCP并没有拥塞控制机制,正是TCP的超时重传风暴(一个分段丢失造成后续的已经发送的分段均被重传,而这些重传大多数是不必要的)加重了网络的拥塞。因此重传必然不能过频,必须把重传定时器的超时时间设置的稍微长一些,而这一点在单一重传定时器的设计中得到了加强。除此TCP自身的因素之外,其它所有的拥塞都可以靠拥塞控制机制来自动完成。

另外,不要把路由器想成一种线速转发设备,再好的路由器只要接入网络,总是会拉低网络的总带宽,因此即使只有一个TCP连接,由于TCP的发送方总是以发送链路的带宽发送分段,这些分段在经过路由器的时候排队和处理总是会有时延,因此最终肯定会丢包的。

最后,丢包的延后性也会加重拥塞。假设一个TCP连接经过了N个路由器,前N-1个路由器都能顺利转发TCP分段,但是最后一个路由器丢失了一个分段,这就导致了这些丢失的分段浪费了前面路由器的大量带宽。

5.2.拥塞控制的策略

在介绍拥塞控制之前,首先介绍一下拥塞窗口,它实际上表示的也是“可以发送多少数据”,然而这个和接收端通告的接收窗口意义是不一样的,后者是流量控制用的窗口,而前者是拥塞控制用的窗口,体现了网络拥塞程度。

拥塞控制整体上分为两类,一类是试探性的拥塞探测,另一类则是拥塞避免(注意,不是常规意义上的拥塞避免)。

5.2.1.试探性的拥塞探测分为两类,之一是慢启动,之二是拥塞窗口加性扩大(也就是熟知的拥塞避免,然而这种方式是避免不了拥塞的)。

5.2.2.拥塞避免方式拥塞控制旨在还没有发生拥塞的时候就先提醒发送端,网络拥塞了,这样发送端就要么可以进入快速重传/快速恢复或者显式的减小拥塞窗口,这样就避免网络拥塞的一沓糊涂之后出现超时,从而进入慢启动阶段。

5.2.3.快速重传和快速恢复。所谓快速重传/快速恢复是针对慢启动的,我们知道慢启动要从1个MSS开始增加拥塞窗口,而快速重传/快速恢复则是一旦收到3个冗余ACK,不必进入慢启动,而是将拥塞窗口缩小为当前阀值的一半加上3,然后如果继续收到冗余ACK,则将拥塞窗口加1个MSS,直到收到一个新的数据ACK,将窗口设置成正常的阀值,开始加性增加的阶段。

当进入快速重传时,为何要将拥塞窗口缩小为当前阀值的一半加上3呢?加上3是基于数据包守恒来说的,既然已经收到了3个冗余ACK,说明有三个数据分段已经到达了接收端,既然三个分段已经离开了网络,那么就是说可以在发送3个分段了,只要再收到一个冗余ACK,这也说明1个分段已经离开了网络,因此就将拥塞窗口加1个MSS。直到收到新的ACK,说明直到收到第三个冗余ACK时期发送的TCP分段都已经到达对端了,此时进入正常阶段开始加性增加拥塞窗口。

疑难杂症17:超时重传和收到3个冗余ACK后重传

这两种重传的意义是不同的,超时重传一般是因为网络出现了严重拥塞(没有一个分段到达,如果有的话,肯定会有ACK的,若是正常ACK,则重置重传定时器,若是冗余ACK,则可能是个别报文丢失或者被重排序,若连续3个冗余ACK,则很有可能是个别分段丢失),此时需要更加严厉的缩小拥塞窗口,因此此时进入慢启动阶段。而收到3个冗余ACK后说明确实有中间的分段丢失,然而后面的分段确实到达了接收端,这因为这样才会发送冗余ACK,这一般是路由器故障或者轻度拥塞或者其它不太严重的原因引起的,因此此时拥塞窗口缩小的幅度就不能太大,此时进入快速重传/快速恢复阶段。

疑难杂症18:为何收到3个冗余ACK后才重传

这是一种权衡的结构,收到两个或者一个冗余ACK也可以重传,但是这样的话可能或造成不必要的重传,因为两个数据分段发生乱序的可能性不大,超过三个分段发生乱序的可能性才大,换句话说,如果仅仅收到一个乱序的分段,那很可能被中间路由器重排了,那么另一个分段很可能马上就到,然而如果连续收到了3个分段都没能弥补那个缺漏,那很可能是它丢失了,需要重传。因此3个冗余ACK是一种权衡,在减少不必要重传和确实能检测出单个分段丢失之间所作的权衡。

注意,冗余ACK是不能捎带的。

疑难杂症19:乘性减和加性增的深层含义

为什么是乘性减而加性增呢?拥塞窗口的增加受惠的只是自己,而拥塞窗口减少受益的大家,可是自己却受到了伤害。哪一点更重要呢?我们知道TCP的拥塞控制中内置了公平性,恰恰就是这种乘性减实现了公平性。拥塞窗口的1个MSS的改变影响一个TCP发送者,为了使得自己拥塞窗口的减少影响更多的TCP发送者-让更多的发送者受益,那么采取了乘性减的策略。

当然,BIC算法提高了加性增的效率,不再一个一个MSS的加,而是一次加比较多的MSS,采取二分查找的方式逐步找到不丢包的点,然后加性增。

疑难杂症20:TCP连接的传输稳定状态是什么

首先,先说一下发送端的发送窗口怎么确定,它取的是拥塞窗口和接收端通告窗口的最小值。然后,我们提出三种发送窗口的稳定状态:

a.IP互联网络上接收端拥有大窗口的经典锯齿状

b.IP互联网络上接收端拥有小窗口的直线状态

c.直连网络端点间的满载状态下的直线状态

其中a是大多数的状态,因为一般而言,TCP连接都是建立在互联网上的,而且是大量的,比如Web浏览,电子邮件,网络游戏,Ftp下载等等。TCP发送端用慢启动或者拥塞避免方式不断增加其拥塞窗口,直到丢包的发生,然后进入慢启动或者拥塞避免阶段(要看是由于超时丢包还是由于冗余ACK丢包),此时发送窗口将下降到1或者下降一半,这种情况下,一般接收端的接收窗口是比较大的,毕竟IP网络并不是什么很快速的网络,一般的机器处理速度都很快。

但是如果接收端特别破,处理速度很慢,就会导致其通告一个很小的窗口,这样的话,即使拥塞窗口再大,发送端也还是以通告的接收窗口为发送窗口,这样就不会发生拥塞。最后,如果唯一的TCP连接运行在一个直连的两台主机上,那么它将独享网络带宽,这样该TCP的数据流在最好的情况下将填满网络管道(我们把网络管道定义为带宽和延时的乘积),其实在这种情况下是不存在拥塞的,就像你一个人独自徘徊在飘雨黄昏的街头一样...

5.2.4.主动的拥塞避免

前面我们描述的拥塞控制方式都是试探性的检测,然后拥塞窗口被动的进行乘性减,这样在接收端窗口很大的情况下(一般都是这样,网络拥堵,分段就不会轻易到达接收端,导致接收端的窗口大量空置)就可能出现锯齿形状的“时间-窗口”图,类似在一个拥堵的北京X环上开车,发送机发动,车开动,停止,等待,发动机发动,车开动...听声音也能听出来。

虽然TCP看不到下面的IP网络,然而它还是可以通过检测RTT的变化以及拥塞窗口的变化推算出IP网络的拥堵情况的。就比方说北京东四环一家快递公司要持续送快递到西四环,当发件人发现货到时间越来越慢的时候,他会意识到“下班高峰期快到了”...

可以通过持续观测RTT的方式来主动调整拥塞窗口的大小而不是一味的加性增。然而还有更猛的算法,那就是计算两个差值的乘积:

(当前拥塞窗口-上一次拥塞窗口)x(当前的RTT-上一次的RTT)

如果结果是正数,则拥塞窗口减少1/8,若结果是负数或者0,则窗口增加一个MSS。注意,这回不再是乘性减了,可以看出,减的幅度比乘性减幅度小,这是因为这种拥塞控制是主动的,而不是之前的那种被动的试探方式。在试探方式中,乘性减以一种惩罚的方式实现了公平性,而在这里的主动方式中,当意识到要拥塞的时候,TCP发送者主动的减少了拥塞窗口,为了对这种自首行为进行鼓励,采用了小幅减少拥塞窗口的方式。需要注意的是,在拥塞窗口减小的过程中,乘积的前一个差值是负数,如果后一个差值也是负数,那么结果就是继续缩减窗口,直到拥塞缓解或者窗口减少到了一定程度,使得后一个差值成了正数或者0,这种情况下,其实后一个差值只能变为0。

疑难杂症21:路由器和TCP的互动

虽然有了5.2.4节介绍的主动的拥塞检测,那么路由器能不能做点什么帮助检测拥塞呢?这种对路由器的扩展是必要的,要知道,每天有无数的TCP要通过路由器,虽然路由器不管TCP协议的任何事(当然排除连接跟踪之类的,这里所说的是标准的IP路由器),但是它却能以一种很简单的方式告诉TCP的两端IP网络发生了拥堵,这种方式就是当路由器检测到自己发生轻微拥堵的时候随机的丢包,随机丢包而不是连续丢包对于TCP而言是有重大意义的,随机丢包会使TCP发现丢弃了个别的分段而后续的分段仍然会到达接收端,这样TCP发送端就会接收到3个冗余ACK,然后进入快速重传/快速恢复而不是慢启动。

这就是路由器能帮TCP做的事。

6.其它

疑难杂症22:如何学习TCP

很多人发帖问TCP相关的内容,接下来稀里哗啦的就是让看《TCP/IP详解》和《Unix网络编程》里面的特定章节,我觉得这种回答很不负责任。因为我并不认为这两本书有多大的帮助,写得确实很不错,然而可以看出Richard Stevens是一个实用主义者,他喜欢用实例来解释一切,《详解》通篇都是用tcpdump的输出来讲述的,这种方式只是适合于已经对TCP很理解的人,然而大多数的人是看不明白的。

如果想从设计的角度来说,这两本书都很烂。我觉得应该先看点入门的,比如Wiki之类的,然后看RFC文档,793,896,1122等),这样你就明白TCP为何这么设计了,而这些你永远都不能在Richard Stevens的书中得到。最后,如果你想,那么就看一点Richard Stevens的书,最重要的还是写点代码或者敲点命令,然后抓包自己去分析。

疑难杂症23:Linux,Windows和网络编程

我觉得在Linux上写点TCP的代码是很不错的,如果有BSD那就更好了。不推荐用Winsock学习TCP。虽然微软声称自己的API都是为了让事情更简单,但实际上事情却更复杂了,如果你用Winsock学习,你就要花大量的时候去掌握一些和网络编程无关但是windows平台上却少不了的东西

6.1.总结

TCP协议是一个端到端的协议,虽然话说它是一个带流量控制,拥塞控制的协议,然而正是因为这些所谓的控制才导致了TCP变得复杂。同时这些特性是互相杂糅的,流量控制带来了很多问题,解决这些问题的方案最终又带来了新的问题,这些问题在解决的时候都只考虑了端到端的意义,但实际上TCP需要尽力而为的IP提供的网络,因此拥塞成了最终的结症,拥塞控制算法的改进也成了一个单独的领域。

在学习TCP的过程中,切忌一锅粥一盘棋的方式,一定要分清楚每一个算法到底是解决什么问题的,每一个问题和其他问题到底有什么关联,这些问题的解决方案之间有什么关联,另外TCP的发展历史也最好了解一下,这些都搞明白了,TCP协议就彻底被你掌控了。接下来你就可以学习Socket API了,然后高效的TCP程序出自你手!

篇5:TCP协议的部分解析

TCP协议的部分解析

说明:

1).本文以TCP的发展历程解析容易引起混淆,误会的方方面面

2).本文不会贴大量的源码,大多数是以文字形式描述,我相信文字看起来是要比代码更轻松的

3).针对对象:对TCP已经有了全面了解的人,因为本文不会解析TCP头里面的每一个字段或者3次握手的细节,也不会解释慢启动和快速重传的定义

4).除了《TCP/IP详解》(卷一,卷二)以及《Unix网络编程》以及Linux源代码之外,学习网络更好的资源是RFC

5).本文给出一个提纲,如果想了解细节,请直接查阅RFC

6).翻来覆去,终于找到了这篇备忘,本文基于这篇备忘文档修改。

1.网络协议设计

ISO提出了OSI分层网络模型,这种分层模型是理论上的,TCP/IP最终实现了一个分层的协议模型,每一个层次对应一组网络协议完成一组特定的功能,该组网络协议被其下的层次复用和解复用。这就是分层模型的本质,最终所有的逻辑被编码到线缆或者电磁波。

分层模型是很好理解的,然而对于每一层的协议设计却不是那么容易。TCP/IP的漂亮之处在于:协议越往上层越复杂。我们把网络定义为互相连接在一起的设备,网络的本质作用还是“端到端”的通信,然而希望互相通信的设备并不一定要“直接”连接在一起,因此必然需要一些中间的设备负责转发数据,因此就把连接这些中间设备的线缆上跑的协议定义为链路层协议,实际上所谓链路其实就是始发与一个设备,通过一根线,终止于另一个设备。我们把一条链路称为“一跳”。因此一个端到端的网络包含了“很多跳”。

2.TCP和IP协议

终止于IP协议,我们已经可以完成一个端到端的通信,为何还需要TCP协议?这是一个问题,理解了这个问题,我们就能理解TCP协议为何成了现在这个样子,为何如此“复杂”,为何又如此简单。

正如其名字所展示的那样,TCP的作用是传输控制,也就是控制端到端的传输,那为何这种控制不在IP协议中实现的。答案很简单,那就是这会增加IP协议的复杂性,而IP协议需要的就是简单。这是什么原因造成的呢?

首先我们认识一下为何IP协议是沙漏的细腰部分。它的下层是繁多的链路层协议,这些链路提供了相互截然不同且相差很远的语义,为了互联这些异构的网络,我们需要一个网络层协议起码要提供一些适配的功能,另外它必然不能提供太多的“保证性服务”,因为上层的保证性依赖下层的约束性更强的保证性,你永远无法在一个100M吞吐量的链路之上实现的IP协议保证1000M的吞吐量...

IP协议设计为分组转发协议,每一跳都要经过一个中间节点,路由的设计是TCP/IP网络的另一大创举,这样,IP协议就无需方向性,路由信息和协议本身不再强关联,它们仅仅通过IP地址来关联,因此,IP协议更加简单。路由器作为中间节点也不能太复杂,这涉及到成本问题,因此路由器只负责选路以及转发数据包。

因此传输控制协议必然需要在端点实现。在我们详谈TCP协议之前,首先要看一下它不能做什么,由于IP协议不提供保证,TCP也不能提供依赖于IP下层链路的这种保证,比如带宽,比如时延,这些都是链路层决定的,既然IP协议无法修补,TCP也不能,然而它却能修正始于IP层的一些“不可保证性质”,这些性质包括IP层的不可靠,IP层的不按顺序,IP层的无方向/无连接。

将该小节总结一下,TCP/IP模型从下往上,功能增加,需要实现的设备减少,然而设备的复杂性却在增加,这样保证了成本的最小化,至于性能或者因素,靠软件来调节吧,TCP协议就是这样的软件,实际上最开始的时候,TCP并不考虑性能,效率,公平性,正是考虑了这些,TCP协议才复杂了起来。

3.TCP协议

这是一个纯软件协议,为何将其设计上两个端点,参见上一小节,本节详述TCP协议,中间也穿插一些简短的论述。

3.1.TCP协议

确切的说,TCP协议有两重身份,作为网络协议,它弥补了IP协议尽力而为服务的不足,实现了有连接,可靠传输,报文按序到达。作为一个主机软件,它和UDP以及左右的传输层协议隔离了主机服务和网络,它们可以被看做是一个多路复用/解复用器,将诸多的主机进程数据复用/解复用到IP层。可以看出,不管从哪个角度,TCP都作为一个接口存在,作为网络协议,它和对端的TCP接口,实现TCP的控制逻辑,作为多路复用/解复用器,它和下层IP协议接口,实现协议栈的功能,而这正是分层网络协议模型的基本定义(两类接口,一类和下层接口,另一类和对等层接口)。

我们习惯于将TCP作为协议栈的最顶端,而不把应用层协议当成协议栈的一部分,这部分是因为应用层被TCP/UDP解复用了之后,呈现出了一种太复杂的局面,应用层协议用一种不同截然不同的方式被解释,应用层协议习惯于用类似ASN.1标准来封装,这正体现了TCP协议作为多路复用/解复用器的重要性,由于直接和应用接口,它可以很容易直接被应用控制,实现不同的传输控制策略,这也是TCP被设计到离应用不太远的地方的原因之一。

总之,TCP要点有四,一曰有连接,二曰可靠传输,三曰数据按照到达,四曰端到端流量控制。注意,TCP被设计时只保证这四点,此时它虽然也有些问题,然而很简单,然而更大的问题很快呈现出来,使之不得不考虑和IP网络相关的东西,比如公平性,效率,因此增加了拥塞控制,这样TCP就成了现在这个样子。

3.2.有连接,可靠传输,数据按序到达的TCP

IP协议是没有方向的,数据报传输能到达对端全靠路由,因此它是一跳一跳地到达对端的,只要有一跳没有到达对端的路由,那么数据传输将失败,其实路由也是互联网的核心之一,实际上IP层提供的核心基本功能有两点,第一点是地址管理,第二点就是路由选路。TCP利用了IP路由这个简单的功能,因此TCP不必考虑选路,这又一个它被设计成端到端协议的原因。

既然IP已经能尽力让单独的数据报到达对端,那么TCP就可以在这种尽力而为的网络上实现其它的更加严格的控制功能。TCP给无连接的IP网络通信增加了连接性,确认了已经发送出去的数据的状态,并且保证了数据的顺序。

3.2.1.有连接

这是TCP的基本,因为后续的传输的可靠性以及数据顺序性都依赖于一条连接,这是最简单的实现方式,因此TCP被设计成一种基于流的协议,既然TCP需要事先建立连接,之后传输多少数据就无所谓了,只要是同一连接的数据能识别出来即可。

疑难杂症1:3次握手和4次挥手

TCP使用3次握手建立一条连接,该握手初始化了传输可靠性以及数据顺序性必要的信息,这些信息包括两个方向的初始序列号,确认号由初始序列号生成,使用3次握手是因为3次握手已经准备好了传输可靠性以及数据顺序性所必要的信息,该握手的第3次实际上并不是需要单独传输的,完全可以和数据一起传输。

TCP使用4次挥手拆除一条连接,为何需要4次呢?因为TCP是一个全双工协议,必须单独拆除每一条信道。注意,4次挥手和3次握手的意义是不同的,很多人都会问为何建立连接是3次握手,而拆除连接是4次挥手。3次握手的目的很简单,就是分配资源,初始化序列号,这时还不涉及数据传输,3次就足够做到这个了,而4次挥手的目的是终止数据传输,并回收资源,此时两个端点两个方向的序列号已经没有了任何关系,必须等待两方向都没有数据传输时才能拆除虚链路,不像初始化时那么简单,发现SYN标志就初始化一个序列号并确认SYN的序列号。因此必须单独分别在一个方向上终止该方向的数据传输。

疑难杂症2:TIME_WAIT状态

为何要有这个状态,原因很简单,那就是每次建立连接的时候序列号都是随机产生的,并且这个序列号是32位的,会回绕。现在我来解释这和TIME_WAIT有什么关系。

任何的TCP分段都要在尽力而为的IP网络上传输,中间的路由器可能会随意的缓存任何的IP数据报,它并不管这个IP数据报上被承载的是什么数据,然而根据经验和互联网的大小,一个IP数据报最多存活MSL(这是根据地球表面积,电磁波在各种介质中的传输速率以及IP协议的TTL等综合推算出来的,如果在火星上,这个MSL会大得多...)。

现在我们考虑终止连接时的被动方发送了一个FIN,然后主动方回复了一个ACK,然而这个ACK可能会丢失,这会造成被动方重发FIN,这个FIN可能会在互联网上存活MSL。

如果没有TIME_WAIT的话,假设连接1已经断开,然而其被动方最后重发的那个FIN(或者FIN之前发送的任何TCP分段)还在网络上,然而连接2重用了连接1的所有的5元素(源IP,目的IP,TCP,源端口,目的端口),刚刚将建立好连接,连接1迟到的FIN到达了,这个FIN将以比较低但是确实可能的概率终止掉连接2.

为何说是概率比较低呢?这涉及到一个匹配问题,迟到的FIN分段的序列号必须落在连接2的一方的期望序列号范围之内。虽然这种巧合很少发生,但确实会发生,毕竟初始序列号是随机产生了。因此终止连接的主动方必须在接受了被动方且回复了ACK之后等待2*MSL时间才能进入CLOSE状态,之所以乘以2是因为这是保守的算法,最坏情况下,针对被动方的ACK在以最长路线(经历一个MSL)经过互联网马上到达被动方时丢失。

为了应对这个问题,RFC793对初始序列号的生成有个建议,那就是设定一个基准,在这个基准之上搞随机,这个基准就是时间,我们知道时间是单调递增的。然而这仍然有问题,那就是回绕问题,如果发生回绕,那么新的序列号将会落到一个很低的值。因此最好的办法就是避开“重叠”,其含义就是基准之上的随机要设定一个范围。

要知道,很多人很不喜欢看到服务器上出现大量的TIME_WAIT状态的连接,因此他们将TIME_WAIT的值设置的很低,这虽然在大多数情况下可行,然而确实也是一种冒险行为。最好的方式就是,不要重用一个连接。

疑难杂症3:重用一个连接和重用一个套接字

这是根本不同的,单独重用一个套接字一般不会有任何问题,因为TCP是基于连接的。比如在服务器端出现了一个TIME_WAIT连接,那么该连接标识了一个五元素,只要客户端不使用相同的源端口,连接服务器是没有问题的,因为迟到的FIN永远不会到达这个连接。记住,一个五元素标识了一个连接,而不是一个套接字(当然,对于BSD套接字而言,服务端的accept套接字确实标识了一个连接)。

3.2.2.传输可靠性

基本上传输可靠性是靠确认号实现的,也就是说,每发送一个分段,接下来接收端必然要发送一个确认,发送端收到确认后才可以发送下一个字节。这个原则最简单不过了,教科书上的“停止-等待”协议就是这个原则的字节版本,只是TCP使用了滑动窗口机制使得每次不一定发送一个字节,但是这是后话,本节仅仅谈一下确认的超时机制。

怎么知道数据到达对端呢?那就是对端发送一个确认,但是如果一直收不到对端的确认,发送端等多久呢?如果一直等下去,那么将无法发现数据的丢失,协议将不可用,如果等待时间过短,可能确认还在路上,因此等待时间是个问题,另外如何去管理这个超时时间也是一个问题。

疑难杂症4:超时时间的计算

绝对不能随意去揣测超时的时间,而应该给出一个精确的算法去计算。毫无疑问,一个TCP分段的回复到达的时间就是一个数据报往返的时间,因此标准定义了一个新的名词RTT,代表一个TCP分段的往返时间。然而我们知道,IP网络是尽力而为的,并且路由是动态的,且路由器会毫无先兆的缓存或者丢弃任何的数据报,因此这个RTT是需要动态测量的,也就是说起码每隔一段时间就要测量一次,如果每次都一样,万事大吉,然而世界并非如你所愿,因此我们需要找到的恰恰的一个“平均值”,而不是一个准确值。

这个平均值如果仅仅直接通过计算多次测量值取算术平均,那是不恰当的,因为对于数据传输延时,我们必须考虑的路径延迟的瞬间抖动,否则如果两次测量值分别为2和98,那么超时值将是50,这个值对于2而言,太大了,结果造成了数据的延迟过大(本该重传的等待了好久才重传),然而对于98而言,太小了,结果造成了过度重传(路途遥远,本该很慢,结果大量重传已经正确确认但是迟到的TCP分段)。

因此,除了考虑每两次测量值的偏差之外,其变化率也应该考虑在内,如果变化率过大,则通过以变化率为自变量的函数为主计算RTT(如果陡然增大,则取值为比较大的正数,如果陡然减小,则取值为比较小的负数,然后和平均值加权求和),反之如果变化率很小,则取测量平均值。这是不言而喻的,这个算法至今仍然工作的很好。

疑难杂症5:超时计时器的管理-每连接单一计时器

很显然,对每一个TCP分段都生成一个计时器是最直接的方式,每个计时器在RTT时间后到期,如果没有收到确认,则重传。然而这只是理论上的合理,对于大多数操作系统而言,这将带来巨大的内存开销和调度开销,因此采取每一个TCP连接单一计时器的设计则成了一个默认的选择。可是单一的计时器怎么管理如此多的发出去的TCP分段呢?又该如何来设计单一的计时器呢。

设计单一计时器有两个原则:1.每一个报文在长期收不到确认都必须可以超时;2.这个长期收不到中长期不能和测量的RTT相隔太远。因此RFC2988定义一套很简单的原则:

a.发送TCP分段时,如果还没有重传定时器开启,那么开启它。

b.发送TCP分段时,如果已经有重传定时器开启,不再开启它。

c.收到一个非冗余ACK时,如果有数据在传输中,重新开启重传定时器。

d.收到一个非冗余ACK时,如果没有数据在传输中,则关闭重传定时器。

我们看看这4条规则是如何做到以上两点的,根据a和c(在c中,注意到ACK是非冗余的),任何TCP分段只要不被确认,超时定时器总会超时的。然而为何需要c呢?只有规则a存在的话,也可以做到原则1。实际上确实是这样的,但是为了不会出现过早重传,才添加了规则c,如果没有规则c,那么万一在重传定时器到期前,发送了一些数据,这样在定时器到期后,除了很早发送的数据能收到ACK外,其它稍晚些发送的数据的ACK都将不会到来,因此这些数据都将被重传。有了规则c之后,只要有分段ACK到来,则重置重传定时器,这很合理,因此大多数正常情况下,从数据的发出到ACK的到来这段时间以及计算得到的RTT以及重传定时器超时的时间这三者相差并不大,一个ACK到来后重置定时器可以保护后发的数据不被过早重传。

这里面还有一些细节需要说明。一个ACK到来了,说明后续的ACK很可能会依次到来,也就是说丢失的可能性并不大,另外,即使真的有后发的TCP分段丢失现象发生,也会在最多2倍定时器超时时间的范围内被重传(假设该报文是第一个报文发出启动定时器之后马上发出的,丢失了,第一个报文的ACK到来后又重启了定时器,又经过了一个超时时间才会被重传)。虽然这里还没有涉及拥塞控制,但是可见网络拥塞会引起丢包,丢包会引起重传,过度重传反过来加重网络拥塞,设置规则c的结果可以缓解过多的重传,毕竟将启动定时器之后发送的数据的重传超时时间拉长了最多一倍左右。最多一倍左右的超时偏差做到了原则2,即“这个长期收不到中长期不能和测量的RTT相隔太远”。

还有一点,如果是一个发送序列的最后一个分段丢失了,后面就不会收到冗余ACK,这样就只能等到超时了,并且超时时间几乎是肯定会比定时器超时时间更长。如果这个分段是在发送序列的靠后的时间发送的且和前面的发送时间相隔时间较远,则其超时时间不会很大,反之就会比较大。

疑难杂症6:何时测量RTT

目前很多TCP实现了时间戳,这样就方便多了,发送端再也不需要保存发送分段的时间了,只需要将其放入协议头的时间戳字段,然后接收端将其回显在ACK即可,然后发送端收到ACK后,取出时间戳,和当前时间做算术差,即可完成一次RTT的测量。

3.2.3.数据顺序性

基本上传输可靠性是靠序列号实现的。

疑难杂症7:确认号和超时重传

确认号是一个很诡异的东西,因为TCP的发送端对于发送出去的一个数据序列,它只要收到一个确认号就认为确认号前面的数据都被收到了,即使前面的某个确认号丢失了,也就是说,发送端只认最后一个确认号。这是合理的,因为确认号是接收端发出的,接收端只确认按序到达的最后一个TCP分段。

另外,发送端重发了一个TCP报文并且接收到该TCP分段的确认号,并不能说明这个重发的报文被接收了,也可能是数据早就被接收了,只是由于其ACK丢失或者其ACK延迟到达导致了超时。值得说明的是,接收端会丢弃任何重复的数据,即使丢弃了重复的数据,其ACK还是会照发不误的。

标准的早期TCP实现为,只要一个TCP分段丢失,即使后面的TCP分段都被完整收到,发送端还是会重传从丢失分段开始的所有报文,这就会导致一个问题,那就是重传风暴,一个分段丢失,引起大量的重传。这种风暴实则不必要的,因为大多数的TCP实现中,接收端已经缓存了乱序的分段,这些被重传的丢失分段之后的分段到达接收端之后,很大的可能性是被丢弃。关于这一点在拥塞控制被引入之后还会提及(问题先述为快:本来报文丢失导致超时就说明网络很可能已然拥塞,重传风暴只能加重其拥塞程度)。

疑难杂症8:乱序数据缓存以及选择确认

TCP是保证数据顺序的,但是并不意味着它总是会丢弃乱序的TCP分段,具体会不会丢弃是和具体实现相关的,RFC建议如果内存允许,还是要缓存这些乱序到来的分段,然后实现一种机制等到可以拼接成一个按序序列的时候将缓存的分段拼接,这就类似于IP协议中的分片一样,但是由于IP数据报是不确认的,因此IP协议的实现必须缓存收到的任何分片而不能将其丢弃,因为丢弃了一个IP分片,它就再也不会到来了。

现在,TCP实现了一种称为选择确认的方式,接收端会显式告诉发送端需要重传哪些分段而不需要重传哪些分段。这无疑避免了重传风暴。

疑难杂症9:TCP序列号的回绕的问题

TCP的序列号回绕会引起很多的问题,比如序列号为s的分段发出之后,m秒后,序列号比s小的序列号为j的分段发出,只不过此时的j比上一个s多了一圈,这就是回绕问题,那么如果这后一个分段到达接收端,这就会引发彻底乱序-本来j该在s后面,结果反而到达前面了,这种乱序是TCP协议检查不出来的。我们仔细想一下,这种情况确实会发生,数据分段并不是一个字节一个字节发送出去的,如果存在一个速率为1Gbps的网络,TCP发送端1秒会发送125MB的数据,32位的序列号空间能传输2的32次方个字节,也就是说32秒左右就会发生回绕,我们知道这个值远小于MSL值,因此会发生的。

有个细节可能会引起误会,那就是TCP的窗口大小空间是序列号空间的一半,这样恰好在满载情况下,数据能填满发送窗口和接收窗口,序列号空间正好够用。然而事实上,TCP的初始序列号并不是从0开始的,而是随机产生的(当然要辅助一些更精妙的算法),因此如果初始序列号比较接近2的32次方,那么很快就会回绕。

当然,如今可以用时间戳选项来辅助作为序列号的一个识别的部分,接收端遇到回绕的情况,需要比较时间戳,我们知道,时间戳是单调递增的,虽然也会回绕,然而回绕时间却要长很多。这只是一种策略,在此不详谈。还有一个很现实的问题,理论上序列号会回绕,但是实际上,有多少TCP的端点主机直接架设在1G的网络线缆两端并且接收方和发送方的窗口还能恰好被同时填满。另外,就算发生了回绕,也不是一件特别的事情,回绕在计算机里面太常见了,只需要能识别出来即可解决,对于TCP的序列号而言,在高速网络(点对点网络或者以太网)的两端,数据发生乱序的可能性很小,因此当收到一个序列号突然变为0或者终止序列号小于起始序列号的情况后,很容易辨别出来,只需要和前一个确认的分段比较即可,如果在一个经过路由器的网络两端,会引发IP数据报的顺序重排,对于TCP而言,虽然还会发生回绕,也会慢得多,且考虑到拥塞窗口(目前还没有引入)一般不会太大,窗口也很难被填满到65536。

3.2.4.端到端的流量控制

端到端的流量控制使用滑动窗口来实现。滑动窗口的原理非常简单,基本就是一个生产者/消费者模型

疑难杂症10:流量控制的真实意义

很多人以为流量控制会很有效的协调两端的流量匹配,确实是这样,但是如果你考虑到网络的利用率问题,TCP的流量控制机制就不那么完美了,造成这种局面的原因在于,滑动窗口只是限制了最大发送的数据,却没有限制最小发送的数据,结果导致一些很小的数据被封装成TCP分段,报文协议头所占的比例过于大,造成网络利用率下降,这就引出了接下来的内容,那就是端到端意义的TCP协议效率。

~~~~~~~~~~~~~~~~~~~~

承上启下

终于到了阐述问题的时候了,以上的TCP协议实现的非常简单,这也是TCP的标准实现,然而很快我们就会发现各种各样的问题。这些问题导致了标准化协会对TCP协议进行了大量的修补,这些修补杂糅在一起让人们有些云里雾里,不知所措。本文档就旨在分离这些杂乱的情况,实际上,根据RFC,这些杂乱的情况都是可以找到其单独的发展轨迹的。

~~~~~~~~~~~~~~~~~~~~

4.端到端意义上的TCP协议效率

4.1.三个问题以及解决

问题1描述:接收端处理慢,导致接收窗口被填满

这明显是速率不匹配引发的问题,然而即使速率不匹配,只要滑动窗口能协调好它们的速率就好,要快都快,要慢都慢,事实上滑动窗口在这一点上做的很好。但是如果我们不得不从效率上来考虑问题的话,事实就不那么乐观了。考虑此时接收窗口已然被填满,慢速的应用程序慢腾腾的读取了一个字节,空出一个位置,然后通告给TCP的发送端,发送端得知空出一个位置,马上发出一个字节,又将接收端填满,然后接收应用程序又一次慢腾腾...这就是糊涂窗口综合症,一个大多数人都很熟悉的词。这个问题极大的浪费了网络带宽,降低了网络利用率。好比从大同拉100吨煤到北京需要一辆车,拉1Kg煤到北京也需要一辆车(超级夸张的一个例子,请不要相信),但是一辆车开到北京的开销是一定的...

问题1解决:窗口通告

对于问题1,很显然问题出在接收端,我们没有办法限制发送端不发送小分段,但是却可以限制接收端通告小窗口,这是合理的,这并不影响应用程序,此时经典的延迟/吞吐量反比律将不再适用,因为接收窗口是满的,其空出一半空间表示还有一半空间有数据没有被应用读取,和其空出一个字节的空间的效果是一样的,因此可以限制接收端当窗口为0时,直接通告给发送端以阻止其继续发送数据,只有当其接收窗口再次达到MSS的一半大小的时候才通告一个不为0的窗口,此前对于所有的发送端的窗口probe分段(用于探测接收端窗口大小的probe分段,由TCP标准规定),全部通告窗口为0,这样发送端在收到窗口不为0的通告,那么肯定是一个比较大的窗口,因此发送端可以一次性发出一个很大的TCP分段,包含大量数据,也即拉了好几十吨的煤到北京,而不是只拉了几公斤。

即,限制窗口通告时机,解决糊涂窗口综合症

问题2描述:发送端持续发送小包,导致窗口闲置

这明显是发送端引起的问题,此时接收端的窗口开得很大,然而发送端却不积累数据,还是一味的发送小块数据分段。只要发送了任和的分段,接收端都要无条件接收并且确认,这完全符合TCP规范,因此必然要限制发送端不发送这样的小分段。

问题2解决:Nagle算法

Nagel算法很简单,标准的Nagle算法为:

IF 数据的大小和窗口的大小都超过了MSS

Then 发送数据分段

ELSE

IF 还有发出的TCP分段的确认没有到来

Then 积累数据到发送队列的末尾的TCP分段

ELSE

发送数据分段

EndIF

EndIF

可是后来,这个算法变了,变得更加灵活了,其中的:

IF 还有发出的TCP分段的确认没有到来

变成了

IF 还有发出的不足MSS大小的TCP分段的确认没有到来

这样如果发出了一个MSS大小的分段还没有被确认,后面也是可以随时发送一个小分段的,这个改进降低了算法对延迟时间的影响,

这个算法体现了一种自适应的策略,越是确认的快,越是发送的快,虽然Nagle算法看起来在积累数据增加吞吐量的同时也加大的时延,可事实上,如果对于类似交互式的应用,时延并不会增加,因为这类应用回复数据也是很快的,比如Telnet之类的服务必然需要回显字符,因此能和对端进行自适应协调。

注意,Nagle算法是默认开启的,但是却可以关闭。如果在开启的情况下,那么它就严格按照上述的算法来执行。

问题3.确认号(ACK)本身就是不含数据的分段,因此大量的确认号消耗了大量的带宽

这是TCP为了确保可靠性传输的规范,然而大多数情况下,ACK还是可以和数据一起捎带传输的。如果没有捎带传输,那么就只能单独回来一个ACK,如果这样的分段太多,网络的利用率就会下降。从大同用火车拉到北京100吨煤,为了确认煤已收到,北京需要派一辆同样的火车空载开到大同去复命,因为没有别的交通工具,只有火车。如果这位复命者刚开着一列火车走,又从大同来了一车煤,这拉煤的哥们儿又要开一列空车去复命了。

问题3的解决:

RFC建议了一种延迟的ACK,也就是说,ACK在收到数据后并不马上回复,而是延迟一段可以接受的时间,延迟一段时间的目的是看能不能和接收方要发给发送方的数据一起回去,因为TCP协议头中总是包含确认号的,如果能的话,就将ACK一起捎带回去,这样网络利用率就提高了。往大同复命的确认者不必开一辆空载火车回大同了,此时北京正好有一批货物要送往大同,这位复命者搭着这批货的火车返回大同。

如果等了一段可以接受的时间,还是没有数据要发往发送端,此时就需要单独发送一个ACK了,然而即使如此,这个延迟的ACK虽然没有等到可以被捎带的数据分段,也可能等到了后续到来的TCP分段,这样它们就可以取最大者一起返回了,要知道,TCP的确认号是收到的按序报文的最后一个字节的后一个字节。最后,RFC建议,延迟的ACK最多等待两个分段的积累确认。

4.2.分析三个问题之间的关联

三个问题导致的结果是相同的,但是要知道它们的原因本质上是不同的,问题1几乎总是出现在接收端窗口满的情况下,而问题2几乎总是发生在窗口闲置的情况下,问题3看起来是最无聊的,然而由于TCP的要求,必须要有确认号,而且一个确认号就需要一个TCP分段,这个分段不含数据,无疑是很小的。

三个问题都导致了网络利用率的降低。虽然两个问题导致了同样的结果,但是必须认识到它们是不同的问题,很自然的将这些问题的解决方案汇总在一起,形成一个全局的解决方案,这就是如今的操作系统中的解决方案。

4.3.问题的杂糅情况

疑难杂症11:糊涂窗口解决方案和Nagle算法

糊涂窗口综合症患者希望发送端积累TCP分段,而Nagle算法确实保证了一定的TCP分段在发送端的积累,另外在延迟ACK的延迟的那一会时间,发送端会利用这段时间积累数据。然而这却是三个不同的问题。Nagle算法可以缓解糊涂窗口综合症,却不是治本的良药。

疑难杂症12:Nagle算法和延迟ACK

延迟ACK会延长ACK到达发送端的时间,由于标准Nagle算法只允许一个未被确认的TCP分段,那无疑在接收端,这个延迟的ACK是毫无希望等待后续数据到来最终进行积累确认的,如果没有数据可以捎带这个ACK,那么这个ACK只有在延迟确认定时器超时的时候才会发出,这样在等待这个ACK的过程中,发送端又积累了一些数据,因此延迟ACK实际上是在增加延迟的代价下加强了Nagle算法。在延迟ACK加Nagle算法的情况下,接收端只有不断有数据要发回,才能同时既保证了发送端的分段积累,又保证了延迟不增加,同时还没有或者很少有空载的ACK。

要知道,延迟ACK和Nagle是两个问题的解决方案。

疑难杂症13:到底何时可以发送数据

到底何时才能发送数据呢?如果单从Nagle算法上看,很简单,然而事实证明,情况还要更复杂些。如果发送端已经排列了3个TCP分段,分段1,分段2,分段3依次被排入,三个分段都是小分段(不符合Nagle算法中立即发送的标准),此时已经有一个分段被发出了,且其确认还没有到来,请问此时能发送分段1和2吗?如果按照Nagle算法,是不能发送的,但实际上它们是可以发送的,因为这两个分段已经没有任何机会再积累新的数据了,新的数据肯定都积累在分段3上了。问题在于,分段还没有积累到一定大小时,怎么还可以产生新的分段?这是可能的,但这是另一个问题,在此不谈。

Linux的TCP实现在这个问题上表现的更加灵活,它是这么判断能否发送的(在开启了Nagle的情况下):

IF (没有超过拥塞窗口大小的数据分段未确认 || 数据分段中包含FIN ) &&

数据分段没有超越窗口边界

Then

IF 分段在中间(上述例子中的分段1和2) ||

分段是紧急模式      ||

通过上述的Nagle算法(改进后的Nagle算法)

Then 发送分段

EndIF

EndIF

曾经我也改过Nagle算法,确切的说不是修改Nagle算法,而是修改了“到底何时能发送数据”的策略,以往都是发送端判断能否发送数据的,可是如果此时有延迟ACK在等待被捎带,而待发送的数据又由于积累不够或者其它原因不能发送,因此两边都在等,这其实在某些情况下不是很好。我所做的改进中对待何时能发送数据又增加了一种情况,这就是“ACK拉”的情况,一旦有延迟ACK等待发送,判断一下有没有数据也在等待发送,如果有的话,看看数据是否大到了一定程度,在此,我选择的是MSS的一半:

IF (没有超过拥塞窗口大小的数据分段未确认 || 数据分段中包含FIN ) &&

数据分段没有超越窗口边界

Then

IF 分段在中间(上述例子中的分段1和2) ||

分段是紧急模式      ||

通过上述的Nagle算法(改进后的Nagle算法)

Then 发送分段

EndIF

ELSE IF 有延迟ACK等待传输        &&

发送队列中有待发送的TCP分段   &&

发送队列的头分段大小大于MSS的一半

Then 发送队列头分段且捎带延迟ACK

EndIF

另外,发送队列头分段的大小是可以在统计意义上动态计算的,也不一定非要是MSS大小的一半。我们发现,这种算法对于交互式网路应用是自适应的,你打字越快,特定时间内积累的分段就越长,对端回复的越快(可以捎带ACK),本端发送的也就越快(以Echo举例会更好理解)。

疑难杂症14:《TCP/IP详解(卷一)》中Nagle算法的例子解读

这个问题在网上搜了很多的答案,有的说RFC的建议,有的说别的。可是实际上这就是一个典型的“竞态问题”:

首先服务器发了两个分段:

数据段12:ack 14

数据段13:ack 14,54:56

然后客户端发了两个分段:

数据段14:ack 54,14:17

数据段15:ack 56,17:18

可以看到数据段14本来应该确认56的,但是确认的却是54。也就是说,数据段已经移出队列将要发送但还未发送的时候,数据段13才到来,软中断处理程序抢占了数据段14的发送进程,要知道此时只是把数据段14移出了队列,还没有更新任何的状态信息,比如“发出但未被确认的分段数量”,此时软中断处理程序顺利接收了分段13,然后更新窗口信息,并且检查看有没有数据要发送,由于分段14已经移出队列,下一个接受发送检查的就是分段15了,由于状态信息还没有更新,因此分段15顺利通过发送检测,发送完成。

可以看Linux的源代码了解相关信息,tcp_write_xmit这个函数在两个地方会被调用,一个是TCP的发送进程中,另一个就是软中断的接收处理中,两者在调用中的竞态就会引起《详解》中的那种情况。注意,这种不加锁的发送方式是合理的,也是最高效的,因此TCP的处理语义会做出判断,丢弃一切不该接收或者重复接收的分段的。

~~~~~~~~~~~~~~~~~~~~

承上启下

又到了该承上启下,到此为止,我们叙述的TCP还都是简单的TCP,就算是简单的TCP,也存在上述的诸多问题,就更别提继续增加TCP的复杂性了。到此为止,我们的TCP都是端到端意义上的,然而实际上TCP要跑在IP网络之上的,而IP网络的问题是很多的,是一个很拥堵网络。不幸的是,TCP的有些关于确认和可靠性的机制还会加重IP网络的拥堵。

~~~~~~~~~~~~~~~~~~~~

5.IP网络之上的TCP

5.1.端到端的TCP协议和IP协议之间的矛盾

端到端的TCP只能看到两个节点,那就是自己和对方,它们是看不到任何中间的路径的。可是IP网络却是一跳一跳的,它们的矛盾之处在于TCP的端到端流量控制必然会导致网络拥堵。因为每条TCP连接的一端只知道它对端还有多少空间用于接收数据,它们并不管到达对端的路径上是否还有这么大的容量,事实上所有连接的这些空间加在一起将瞬间超过IP网络的容量,因此TCP也不可能按照滑动窗口流量控制机制很理想的运行。

势必需要一种拥塞控制机制,反应路径的拥塞情况。

疑难杂症15:拥塞控制的本质

由于TCP是端到端协议,因此两端之间的控制范畴属于流量控制,IP网络的拥塞会导致TCP分段的丢失,由于TCP看不到中间的路由器,因此这种丢失只会发生中间路由器,当然两个端点的网卡或者IP层丢掉数据分段也是TCP看不到的。因此拥塞控制必然作用于IP链路。事实上我们可以得知,只有在以下情况下拥塞控制才会起作用:

a.两个或两个以上的连接(其中一个一定要是TCP,另一个可以是任意连接)经过同一个路由器或者同一个链路时;

b.只有一个TCP连接,然而它经过了一个路由器时。

其它情况下是不会拥塞的。因为一个TCP总是希望独享整条网络通路,而这对于多个连接而言是不可能的,必须保证TCP的公平性,这样这种拥塞控制机制才合理。本质上,拥塞的原因就是大家都想独享全部带宽资源,结果导致拥塞,这也是合理的,毕竟TCP看不到网络的状态,同时这也决定了TCP的拥塞控制必须采用试探性的方式,最终到达一个足以引起其“反应”的“刺激点”。

拥塞控制需要完成以下两个任务:1.公平性;2.拥塞之后退出拥塞状态。

疑难杂症16:影响拥塞的因素

我们必须认识到拥塞控制是一个整体的机制,它不偏向于任何TCP连接,因此这个机制内在的就包含了公平性。那么影响拥塞的因素都有什么呢?具有讽刺意味的是,起初TCP并没有拥塞控制机制,正是TCP的超时重传风暴(一个分段丢失造成后续的已经发送的分段均被重传,而这些重传大多数是不必要的)加重了网络的拥塞。因此重传必然不能过频,必须把重传定时器的超时时间设置的稍微长一些,而这一点在单一重传定时器的设计中得到了加强。除此TCP自身的因素之外,其它所有的拥塞都可以靠拥塞控制机制来自动完成。

另外,不要把路由器想成一种线速转发设备,再好的路由器只要接入网络,总是会拉低网络的总带宽,因此即使只有一个TCP连接,由于TCP的发送方总是以发送链路的带宽发送分段,这些分段在经过路由器的时候排队和处理总是会有时延,因此最终肯定会丢包的。

最后,丢包的延后性也会加重拥塞。假设一个TCP连接经过了N个路由器,前N-1个路由器都能顺利转发TCP分段,但是最后一个路由器丢失了一个分段,这就导致了这些丢失的分段浪费了前面路由器的大量带宽。

5.2.拥塞控制的策略

在介绍拥塞控制之前,首先介绍一下拥塞窗口,它实际上表示的也是“可以发送多少数据”,然而这个和接收端通告的接收窗口意义是不一样的,后者是流量控制用的窗口,而前者是拥塞控制用的窗口,体现了网络拥塞程度。

拥塞控制整体上分为两类,一类是试探性的拥塞探测,另一类则是拥塞避免(注意,不是常规意义上的拥塞避免)。

5.2.1.试探性的拥塞探测分为两类,之一是慢启动,之二是拥塞窗口加性扩大(也就是熟知的拥塞避免,然而这种方式是避免不了拥塞的)。

5.2.2.拥塞避免方式拥塞控制旨在还没有发生拥塞的时候就先提醒发送端,网络拥塞了,这样发送端就要么可以进入快速重传/快速恢复或者显式的减小拥塞窗口,这样就避免网络拥塞的一沓糊涂之后出现超时,从而进入慢启动阶段。

5.2.3.快速重传和快速恢复。所谓快速重传/快速恢复是针对慢启动的,我们知道慢启动要从1个MSS开始增加拥塞窗口,而快速重传/快速恢复则是一旦收到3个冗余ACK,不必进入慢启动,而是将拥塞窗口缩小为当前阀值的一半加上3,然后如果继续收到冗余ACK,则将拥塞窗口加1个MSS,直到收到一个新的数据ACK,将窗口设置成正常的阀值,开始加性增加的阶段。

当进入快速重传时,为何要将拥塞窗口缩小为当前阀值的一半加上3呢?加上3是基于数据包守恒来说的,既然已经收到了3个冗余ACK,说明有三个数据分段已经到达了接收端,既然三个分段已经离开了网络,那么就是说可以在发送3个分段了,只要再收到一个冗余ACK,这也说明1个分段已经离开了网络,因此就将拥塞窗口加1个MSS。直到收到新的ACK,说明直到收到第三个冗余ACK时期发送的TCP分段都已经到达对端了,此时进入正常阶段开始加性增加拥塞窗口。

疑难杂症17:超时重传和收到3个冗余ACK后重传

这两种重传的意义是不同的,超时重传一般是因为网络出现了严重拥塞(没有一个分段到达,如果有的话,肯定会有ACK的,若是正常ACK,则重置重传定时器,若是冗余ACK,则可能是个别报文丢失或者被重排序,若连续3个冗余ACK,则很有可能是个别分段丢失),此时需要更加严厉的缩小拥塞窗口,因此此时进入慢启动阶段。而收到3个冗余ACK后说明确实有中间的分段丢失,然而后面的分段确实到达了接收端,这因为这样才会发送冗余ACK,这一般是路由器故障或者轻度拥塞或者其它不太严重的原因引起的,因此此时拥塞窗口缩小的幅度就不能太大,此时进入快速重传/快速恢复阶段。

疑难杂症18:为何收到3个冗余ACK后才重传

这是一种权衡的结构,收到两个或者一个冗余ACK也可以重传,但是这样的话可能或造成不必要的重传,因为两个数据分段发生乱序的可能性不大,超过三个分段发生乱序的可能性才大,换句话说,如果仅仅收到一个乱序的分段,那很可能被中间路由器重排了,那么另一个分段很可能马上就到,然而如果连续收到了3个分段都没能弥补那个缺漏,那很可能是它丢失了,需要重传。因此3个冗余ACK是一种权衡,在减少不必要重传和确实能检测出单个分段丢失之间所作的权衡。

注意,冗余ACK是不能捎带的。

疑难杂症19:乘性减和加性增的深层含义

为什么是乘性减而加性增呢?拥塞窗口的增加受惠的只是自己,而拥塞窗口减少受益的大家,可是自己却受到了伤害。哪一点更重要呢?我们知道TCP的拥塞控制中内置了公平性,恰恰就是这种乘性减实现了公平性。拥塞窗口的1个MSS的改变影响一个TCP发送者,为了使得自己拥塞窗口的减少影响更多的TCP发送者-让更多的发送者受益,那么采取了乘性减的策略。

当然,BIC算法提高了加性增的效率,不再一个一个MSS的加,而是一次加比较多的MSS,采取二分查找的方式逐步找到不丢包的点,然后加性增。

疑难杂症20:TCP连接的传输稳定状态是什么

首先,先说一下发送端的发送窗口怎么确定,它取的是拥塞窗口和接收端通告窗口的最小值。然后,我们提出三种发送窗口的稳定状态:

a.IP互联网络上接收端拥有大窗口的经典锯齿状

b.IP互联网络上接收端拥有小窗口的直线状态

c.直连网络端点间的满载状态下的直线状态

其中a是大多数的状态,因为一般而言,TCP连接都是建立在互联网上的,而且是大量的,比如Web浏览,电子邮件,网络游戏,Ftp下载等等。TCP发送端用慢启动或者拥塞避免方式不断增加其拥塞窗口,直到丢包的发生,然后进入慢启动或者拥塞避免阶段(要看是由于超时丢包还是由于冗余ACK丢包),此时发送窗口将下降到1或者下降一半,这种情况下,一般接收端的接收窗口是比较大的,毕竟IP网络并不是什么很快速的网络,一般的机器处理速度都很快。

但是如果接收端特别破,处理速度很慢,就会导致其通告一个很小的窗口,这样的话,即使拥塞窗口再大,发送端也还是以通告的接收窗口为发送窗口,这样就不会发生拥塞。最后,如果唯一的TCP连接运行在一个直连的两台主机上,那么它将独享网络带宽,这样该TCP的数据流在最好的情况下将填满网络管道(我们把网络管道定义为带宽和延时的乘积),其实在这种情况下是不存在拥塞的,就像你一个人独自徘徊在飘雨黄昏的街头一样...

5.2.4.主动的拥塞避免

前面我们描述的拥塞控制方式都是试探性的检测,然后拥塞窗口被动的进行乘性减,这样在接收端窗口很大的情况下(一般都是这样,网络拥堵,分段就不会轻易到达接收端,导致接收端的窗口大量空置)就可能出现锯齿形状的“时间-窗口”图,类似在一个拥堵的北京X环上开车,发送机发动,车开动,停止,等待,发动机发动,车开动...听声音也能听出来。

虽然TCP看不到下面的IP网络,然而它还是可以通过检测RTT的变化以及拥塞窗口的变化推算出IP网络的拥堵情况的。就比方说北京东四环一家快递公司要持续送快递到西四环,当发件人发现货到时间越来越慢的时候,他会意识到“下班高峰期快到了”...

可以通过持续观测RTT的方式来主动调整拥塞窗口的大小而不是一味的加性增。然而还有更猛的算法,那就是计算两个差值的乘积:

(当前拥塞窗口-上一次拥塞窗口)x(当前的RTT-上一次的RTT)

如果结果是正数,则拥塞窗口减少1/8,若结果是负数或者0,则窗口增加一个MSS。注意,这回不再是乘性减了,可以看出,减的幅度比乘性减幅度小,这是因为这种拥塞控制是主动的,而不是之前的那种被动的试探方式。在试探方式中,乘性减以一种惩罚的方式实现了公平性,而在这里的主动方式中,当意识到要拥塞的时候,TCP发送者主动的减少了拥塞窗口,为了对这种自首行为进行鼓励,采用了小幅减少拥塞窗口的方式。需要注意的是,在拥塞窗口减小的过程中,乘积的前一个差值是负数,如果后一个差值也是负数,那么结果就是继续缩减窗口,直到拥塞缓解或者窗口减少到了一定程度,使得后一个差值成了正数或者0,这种情况下,其实后一个差值只能变为0。

疑难杂症21:路由器和TCP的互动

虽然有了5.2.4节介绍的主动的拥塞检测,那么路由器能不能做点什么帮助检测拥塞呢?这种对路由器的扩展是必要的,要知道,每天有无数的TCP要通过路由器,虽然路由器不管TCP协议的任何事(当然排除连接跟踪之类的,这里所说的是标准的IP路由器),但是它却能以一种很简单的方式告诉TCP的两端IP网络发生了拥堵,这种方式就是当路由器检测到自己发生轻微拥堵的时候随机的丢包,随机丢包而不是连续丢包对于TCP而言是有重大意义的,随机丢包会使TCP发现丢弃了个别的分段而后续的分段仍然会到达接收端,这样TCP发送端就会接收到3个冗余ACK,然后进入快速重传/快速恢复而不是慢启动。

这就是路由器能帮TCP做的事。

6.其它

疑难杂症22:如何学习TCP

很多人发帖问TCP相关的内容,接下来稀里哗啦的就是让看《TCP/IP详解》和《Unix网络编程》里面的特定章节,我觉得这种回答很不负责任。因为我并不认为这两本书有多大的帮助,写得确实很不错,然而可以看出Richard Stevens是一个实用主义者,他喜欢用实例来解释一切,《详解》通篇都是用tcpdump的输出来讲述的,这种方式只是适合于已经对TCP很理解的人,然而大多数的人是看不明白的。

如果想从设计的角度来说,这两本书都很烂。我觉得应该先看点入门的,比如Wiki之类的,然后看RFC文档,793,896,1122等),这样你就明白TCP为何这么设计了,而这些你永远都不能在Richard Stevens的书中得到。最后,如果你想,那么就看一点Richard Stevens的书,最重要的还是写点代码或者敲点命令,然后抓包自己去分析。

疑难杂症23:Linux,Windows和网络编程

我觉得在Linux上写点TCP的代码是很不错的,如果有BSD那就更好了。不推荐用Winsock学习TCP。虽然微软声称自己的API都是为了让事情更简单,但实际上事情却更复杂了,如果你用Winsock学习,你就要花大量的时候去掌握一些和网络编程无关但是windows平台上却少不了的东西

6.1.总结

TCP协议是一个端到端的协议,虽然话说它是一个带流量控制,拥塞控制的协议,然而正是因为这些所谓的控制才导致了TCP变得复杂。同时这些特性是互相杂糅的,流量控制带来了很多问题,解决这些问题的方案最终又带来了新的问题,这些问题在解决的时候都只考虑了端到端的意义,但实际上TCP需要尽力而为的IP提供的网络,因此拥塞成了最终的结症,拥塞控制算法的改进也成了一个单独的领域。

在学习TCP的过程中,切忌一锅粥一盘棋的方式,一定要分清楚每一个算法到底是解决什么问题的,每一个问题和其他问题到底有什么关联,这些问题的解决方案之间有什么关联,另外TCP的发展历史也最好了解一下,这些都搞明白了,TCP协议就彻底被你掌控了。接下来你就可以学习Socket API了,然后高效的TCP程序出自你手!

篇6:RIP协议的结构解析

在RIP的学习中,我们了解了它的概念以及特点和版本的内容,这里我们主要分析一下RIP协议的基础结构。通过我们的介绍,相信大家对RIP协议的分组格式能有一个具体的了解.跟大多数分组格式类似的结构.在这里路由协议的分组格式也不是难于理解的.

RIP协议的分组格式

下面描述IP RIP和IP RIP2的分组格式.

1、RIP协议分组格式

命令--表示该分组是请求还是响应.请求分组要求路由器发送其路由表的全部或部分.

响应分组可以是主动提供的周期性路由更新或对请求的响应.大的路由表可以使用多个RIP分组来传递信息.

版本号--指明使用的RIP版本,此域可以通知不同版本的不兼容.

零--未使用.

地址族标志(AFI)--指明使用的地址族.RIP设计用于携带多种不同协议的路由信息.

每个项都有地址族标志来表明使用的地址类型,IP的AFI是2.

地址--指明该项的IP地址.

metric--表示到目的的过程中经过了多少跳数(路由器数).有效路径的值在1和15之间,16表示不可达路径.

注:在一个IP RIP协议分组中最多可有25个AFI、地址和metric域,即一个RIP分组中最多可含有25个地址项.

2、RIP2分组格式

RIP2规范(RFC1723)允许RIP分组包含更多的信息,并提供了简单的认证机制.

命令--表示该分组是请求还是响应.请求分组要求路由器发送其路由表的全部或部分.

响应分组可以是主动提供的周期性路由更新或对请求的响应.大的路由表可以使用多个RIP分组来传递信息.

版本--指明使用的RIP版本,在实现RIP2或进行认证的RIP协议分组中,此值为2.

未使用--值为0.

地址族标志(AFI)--指明使用的地址族.RIP设计用于携带多种不同协议的路由信息.每个项都有地址族标志来表明使用的地址类型,IP的AFI是2.

如果第一项的AFI为0xFFFF,该项剩下的部分就是认证信息.目前,唯一的认证类型就是简单的口令.

路由标记--提供区分内部路由(由RIP学得)和外部路由(由其它协议学得)的方法.

IP地址--指明该项的IP地址.

子网掩码--包含该项的子网掩码.如果此域为0,则该项不指定子网掩码.

下一跳--指明下一跳的IP地址.

metric--表示到目的的过程中经过了多少跳数(路由器数).有效路径的值在1和15之间,16表示不可达路径.

注:在一个IP RIP协议分组中最多可有25个AFI、地址和metric域,即一个RIP分组中最多可含有25个地址项. 如果AFI指明为认证信息,则只能有24个路由表项.

篇7:仲裁协议第三人之解析

仲裁协议第三人之解析

所谓仲裁协议的第三人是指非仲裁协议签订者,因合同转让等缘故成为仲裁当事人,直接提起或者被提起仲裁。从《解释》的规定来看,仲裁协议第三人问题主要包括当事人变更时,仲裁协议对继受者效力;合同权利义务转让时,仲裁协议对受让人效力两个方面的问题:

(一) 当事人变更时仲裁协议对继受者的效力

仲裁当事人变更是指在仲裁程序的进行中,由于特殊事由,仲裁当事人由程序以外的人取代参加程序的情形。作为自然人一方的当事人死亡、作为法人的一方当事人的合并、分立都会导致仲裁当事人的变更,则仲裁协议对继受者的效力如何?

1、因自然人死亡引起的仲裁当事人变更时仲裁协议效力的认定

自然人死亡的后果是在法律上产生继承,即死亡人的权利义务由其继承人承受。虽然继承人并不是该案仲裁协议的一方当事人,但因其继承了被继承人所有的权利和义务(专属于被继承人的'权利除外),而这些权利义务应包括被继承人根据仲裁协议进行仲裁的权利和义务,所以应当认定继承人已取代被继承人在仲裁程序中的地位,享有被继承人的权利,承担了被继承人的义务,进而成为仲裁当事人。英国 年《仲裁法》对此有明确规定:“除非当事人另有约定,仲裁协议不因一方当事人的死亡而解除,其仍可由或向该当事人的个人代表执行。”由于我国仲裁法对此未予明确规定,因而《解释》第8 条规定,除非当事人另有约定,则当事人订立仲裁协议死亡的,仲裁协议对其权利义务的继承者有效。

2、因法人合并、分立引起仲裁当事人变更时仲裁协议效力的认定

法人合并是指两个或者两个以上的独立法人,经法定程序成为一个法人的情形。而法人的分立则是指一个法人经法定程序分立成两个或者两个以上独立法人的情形。合并后的法人概括性地全部继承法人合并时合并各方的权利和义务。因此一方或者双方当事人与其他非仲裁协议签字方发生合并后,合并后的法人就继承了原仲裁协议签字方的权利义务,包括仲裁中的权利和义务,取代了原仲裁当事人的法律地位,成为该案的仲裁当事人。法人的分立也是当事人变更的一种情形。我国《合同法》第90 条规定当事人订立合同后分立的,除债权人和债务人另有约定的以外,由分立的法人或者其他组织对合同的权利和义务享有连带债权,承担债务。“法人分立后,其权利义务由分立后的法人连带继承,因此,原仲裁协议对承受权利义务的分立后的法人具有约束力,除非当事人另有约定。我国仲裁法对此问题未作出明确规定,而按照各国法律的一般规定:”仲裁协议和其他合同一样,对公司的全财产继承人有效。“《解释》明确规定了此种情形下仲裁协议的效力问题:除非当事人在订立仲裁协议时另有约定,则当事人订立仲裁协议后合并、分立的,仲裁协议对其权利义务的继受者有效。法人被撤销、解散和宣告破产而终止,亦属于仲裁当事人变更的一种情形。法人被撤销、解散或者宣告破产,其权利义务由作出撤销或者解散的主管机关或者清算组织继受,则原来的仲裁协议对承受被撤销或者被解散的主管机关或者破产清算组织亦应有效。《解释》却未对法人被撤销、解散或者宣告破产时,仲裁协议对继受者的效力问题作出规定,实属遗憾。

(二) 合同转让时仲裁协议对受让人的效力

合同转让是指合同有效成立后,履行完毕前,合同的一方或者双方当事人将合同的全部或者部分权利义务转让给第三人。不同国家的法律对于合同权利义务转让时,仲裁协议对受让人是否有效采取了不同的态度。比如德国法对此是予以肯定的。而法国以及纽约洲法则认为仲裁协议主要是创设了义务而非权利,并因而要求受让方明确的同意,才能对该方当事人产生效力。瑞典最高法院则采取了中间立场,即如果当事人未明确作出其他约定,则仲裁条款被推定是可以转让的,但是,一旦转让,其仅在受让人实际或者推定知悉仲裁条款的情况下,才对受让人发生作用。由于我国仲裁法对此问题未作出明确规定,各地部分法院多以此种情形下不存在仲裁协议为由否定了此类仲裁协议的效力。合同转让后,新的合同主体取代了原来的合同主体或者新的合同主体与原合同主体成为合同共同体。但无论合同主体如何变更,合同的内容并未因此发生变化,新的合同主体应受原合同中仲裁条款的约束,这一约束应当也及于仲裁条款。最高人民法院在 年5 月12 日的法经(1998)212 号函中对此予以确认:合同的转让方与合同的另一方当事人所签订的仲裁条款对受让人和合同的另一方当事人具有约束力。最高人民法院在《解释》中对此问题采取了与上述瑞典最高法院相似立场,即当事人对此问题未作其他约定,则债权债务全部或者部分转让的,仲裁协议对受让人有效。但在受让债权债务时,受让人明确反对或者不知道有单独仲裁协议,则仲裁协议对债权债务的受让人不产生拘束力。

篇8:彻底弄懂oracle硬解析、软解析、软软解析

硬解析和软解析有相同的一步,而软软解析与硬解析、软解析完全不一样,先来说下理论上的东西,然后来做个实验。

硬解析过程:

1.语法、语义及权限检查;

2.查询转换(通过应用各种不同的转换技巧,会生成语义上等同的新的SQL语句,如count(1)会转为count(*));

3.根据统计信息生成执行计划(找出成本最低的路径,这一步比较耗时);

4.将游标信息(执行计划)保存到库缓存。

软解析过程:

1.语法、语义及权限检查;

2.将整条SQL hash后从库缓存中执行计划。

软解析对比硬解析省了三个步骤。

软软解析过程:

要完全理解软软解析先要理解游标的概念,当执行SQL时,首先要打开游标,执行完成后,要关闭游标,游标可以理解为SQL语句的一个句柄。

在执行软软解析之前,首先要进行软解析,MOS上说执行3次的SQL语句会把游标缓存到PGA,这个游标一直开着,当再有相同的SQL执行时,则跳过解析的所有过程直接去取执行计划。

SQL>drop table test purge;

SQL>alter system flush shared_pool;

SQL>create table test as select * from dba_objects where 11;

SQL>exec dbms_stats.gather_table_stats(user,'test');

硬解析:

SQL>select * from test where object_id=20;

未选定行

SQL>select * from test where object_id=30;

未选定行

SQL>select * from test where object_id=40;

未选定行

SQL>select * from test where object_id=50;

未选定行

软解析:

SQL>var oid number;

SQL>exec :oid:=20;

SQL>select * from test where object_id=:oid;

未选定行

SQL>exec :oid:=30;

SQL>select * from test where object_id=:oid;

未选定行

SQL>exec :oid:=40;

SQL>select * from test where object_id=:oid;

未选定行

SQL>exec :oid:=50;

SQL>select * from test where object_id=:oid;

未选定行

软软解析:

SQL>begin

for i in 1..4 loop

execute immediate 'select * from test where object_id=:i' using i;

end loop;

end;

/

SQL>col sql_text format a40

SQL>select sql_text,s.PARSE_CALLS,loads,executions from v$sql s

where sql_text like 'select * from test where object_id%'

order by 1,2,3,4;

SQL_TEXT PARSE_CALLS LOADS EXECUTIONS

---------------------------------------- ----------- ---------- ----------

select * from test where object_id=20 1 1 1

select * from test where object_id=30 1 1 1

select * from test where object_id=40 1 1 1

select * from test where object_id=50 1 1 1

select * from test where object_id=:i 1 1 4

select * from test where object_id=:oid 4 1 4

可以看到软解析与软软解析相比,软软解析只是解析一次,

字段解释:

PARSE_CALLS 解析的次数

LOADS 硬解析的次数

EXECUTIONS 执行的次数

篇9:无线软AP的未来前景的简要解析

网络和板卡厂商的“战争”

较早提出软AP理论的是Circond推出的SoftAP和Pctel(美国国际远届科技)公司的软件SAM。

Pctel是全球知名的无线解决方案与存取技术商,其最早引人注目的产品就是全软型的内置猫。Pctel在销售HSP前一直是销售“软”猫的,而且Pctel公司一直致力于 WLAN软件的开发,其主要方向就在于简化配置和使用无线网络的步骤。而英特尔公司曾向Wi-FI技术开发商PCTel公司支付1450万美元,以便获得该公司Wi-Fi专利技术的全部使用权,足见该公司的实力。

Pctel的SAM与Circond推出的SoftAP产品非常类似,两者都可以让某台带有Wi-Fi(无线局域网)网卡通过有线宽带接入互联网的电脑正常工作,又可以成为一个无线接入点,从而省下购买专门的无线接入点的开支。Circond的SoftAP需要在作为接入点的电脑和连接到接入点的其它电脑都要装上软件才能组成一个网络,而Pctel的SAM只需在那台作接入点的电脑装备软件,其余从机只需要有无线网卡即可。

目前厂商推出的无线软AP大多基于这两家产品的理论。Pctel的SAM主要销售给ODM、OEM和芯片厂商,通过这样让SAM成为每台Wi-Fi产品的标准配置,如SIS(矽统)推出的SiS162无线网卡就是采用PCTEL Segue Roaming Client软件,提供符合IEEE 802.11x规格的无线软AP功能。

而真正让无线软AP这个概念全面走向前台的是华硕和微星两大板卡巨头,这两者不仅在主板和显卡领域是全球最大的两霸,而且在无线产品个性化、主板产品无线化技术的推广上亦走在前列。

例如,除了主板无线软AP产品外,华硕推出了一系列的新型软AP无线网卡,如WL-107g、WL-138G等,该系列产品最大的特点在于可以通过软件仿真的方式将你的电脑武装成为一台无线软AP并支持WDS与NAT功能。

而微星科技推出的54G系列无线通讯产品CB54G2、PC54G2等也具备类似功能,这两款产品在Windows XP下都支持软AP/路由,

但我们可以看到,与主板厂商对软AP的热衷不同,传统的网络产品厂商对此大都不闻不问。在更注重现实的传统的网络产品厂商眼中,面对主板厂商来势汹汹欲冲击传统网络市场的无线软AP,传统的网络产品厂商多数认为其要想在功能和市场上取带无线AP并不看好。

关键的关键还有价格

尽管传统网络产品厂商对无线软AP不看好,但也没影响华硕、微星等主板厂商对无线软AP推广的热情。而且随着这些一线大厂对主板板载无线产品的强势推广,在未来更多的具备软AP功能的产品将被其它主板品牌厂商做为主板一项重要的新功能推出。但真正影响具备软AP功能的独立无线网卡在市场上推广的主要因素还是价格。

例如,目前具备软AP功能的微星CB54G2无线网卡,其市场指导价格是280元左右,这样的价格比传统网络产品厂商的同类无线网卡产品接近贵上一半。而同一些低价无线AP/路由产品相比,其也不具备性价比优势,目前D-LINK、TP-LINK等厂商的低价无线路由器其价格已降到300元左右,其无论在性能还是使用便利性上都明显高于无线软AP产品。

所以,摆在板卡厂商面前的独立无线软AP之路还有很长要走。而其中最关键的一点是其产品要想得到更多的认同,就是必需在价格上能压制住传统网络产品厂商的无线网卡产品。

后话

我们在此介绍软AP,并不是想全盘否定它或吹捧它。做为一种新概念产品,其存在既有其一定的合理性,虽然普通无线网卡亦能具备同样的功能,但无可否认软 AP也有其使用的便利性。虽然传统网络产品厂商对无线软AP不看好,但也并不意味着可以对其一棒打死。做为成熟的消费者,我们在看待这种事物时应更具理性,软 AP存在就意味着合理,特别是对于其在主板板载领域而言更是如此。

当然,对于无线软AP产品而言,最需强调的还是价格,价格是其想在市场上赢得成功的最关键因素。我们可以看到,无论是目前的独立软AP或是板载软AP,其产品都在价格基本缺少竟争力。所以,对于主板厂商而言,其要想通过无线软AP产品在传统网络产品厂商的固有市场上取得成功,最需在这方面多努力才行。

此外,相比普通无线网卡,软AP整合化的驱动/软件可为初接触网络的用户提供软AP安装很大的使用便利,初级用户不需要为此特别的钻研LAN网络知识,只需按照说明书一步步“Next”就能完成无线软AP的配置。这对新手而言还是很具积极意义的。

总之,无线软AP这类产品为初级用户和注重价格的用户提供了一种可选的解决方案,但它要真正受到用户的欢迎,仍需在“替补席”上多做努力方行。

篇10:基于编译技术的协议解析方法

基于编译技术的协议解析方法

摘 要:在过程工业的控制中存在着大量的通信协议,这些协议的结构差别很大。要进行上层应用开发,必须对这些协议进行解析和处理。该文讨论了用形式化描述的方法对协议进行描述,实现了与协议无关的协议解析和处理,从而避免了针对不同通信协议均要编写相应的解析和处理程序,使协议的解析和处理具有更好的灵活性和普适性。

关键词:协议分析;数据帧;编译技术

在过程工业中,工业自动化技术日趋成熟,自动化控制系统的应用已经非常普及,但是各类控制系统绝大多数是封闭的系统,控制装置自身存在封闭性。不同的厂家为各自的产品提供不同的协议和通信方式,缺乏统一的、标准的开放式接口。如果要集成在一起,必须为它们开发专用的通信接口。随着工业自动化系统功能要求越来越复杂,完全用一个厂家的产品来构成整个系统是很困难的。用户在进行上层应用程序开发的时候,通常需要对协议进行解析,从中提取出所需数据项,并进行相应的存储、加工计算和显示等处理,这就要求用户不得不针对特定的控制系统开发特定的、专用的通信接口代写论文。

这些通信接口程序之间的结构非常类似,主要的区别在于对网络接口收到数据帧的理解和解释不同,极易造成整个应用系统的复杂和冗余。更为不利的是,一旦底层设备发生变化,就可能造成整个应用程序的重新编写和编译,大大增加了系统的维护量和开发人员的负担[1]。

1 控制设备协议分析

对于不同控制系统中的控制协议,其数据帧格式往往不同。但是在特定的控制系统中所涉及到的数据帧通常都有明确的格式定义,并且数据帧与数据帧之间往往是相对独立的。更为重要的是控制系统中的设备要完成通信功能必须在物理链路上建立逻辑连接。这里的物理链路包括以太网、串行口等,相应的逻辑连接是TCP/IP 协议、串行通信协议,在此基础上各种设备再定义自己的应用层协议。虽然应用层协议的.类别会因设备和厂家的不同而有很大的变化,但是仔细分析就会发现,这些协议都各自具有确定的帧格式,如哪些字节表示命令、哪些字节表示参数名、哪些字节表示设备位号、哪些字节表示数值等。

既然所有的通信协议都遵守一定的帧格式,那么就可以根据已知的帧格式构造此协议的解析程序,针对每一种通信协议手工编写这样的解析程序是没有问题的,本文讨论的是能不能将通信协议数据帧格式的描述与协议的解析代码相分离,用稳定的程序来处理不稳定的数据帧格式。如果答案肯定,那么就能对不同设备采用同一个接口采集数据,如果底层设备的通信协议发生变化,只需要改变协议相应的描述,而不必重新编写和编译协议的解析程序,可以降低系统的复杂度,便于管理和扩充。

2 协议解析的解决方案

如前所述,编译原理中的基本词法分析和语法分析的思想为解决所面临的问题提供了理论基础,特别是词法分析器自动生成器和语法分析器自动生成器提供了很好的借鉴方法[2]。词法分析器自动生成器的基本实现思想是:(1)对输入流进行形式化描述生成一个状态转换图,根据此状态图可以识别此种输入流的所有形式;(2)由一个主控程序根据状态转换图对输入流进行扫描分析以识别符合描述的短语。把这种思想运用到本文所面临的问题上,问题的解决方案就可描述为:(1)把设备的通信协议形式化描述(描述的方式即采用正规式集的方式);(2)由一个状态图生成程序产生对应这些正规式的状态图(在下文中把状态图称为驱动表、相应的状态图生成程序称为驱动表自动构造器);(3)由一个唯一的主控程序根据此驱动表对接收到的数据帧进行分析识别,输出用户希望的数据格式。

2.1 总体设计方案

本文提出一种根据用户配置文件自动进行协议数据识别的解决方案,该方案主要由以下部分构成,即用户配置文件、词法分析器自动生成器、语法分析器自动生成器、数据帧识别器,方案结构如图1 所示。用户配置文件协议形式化描述语法规则配置词法分析器自动生成器语法分析器自动生成器数据帧识别器数据帧 数据帧分析结果图1 总体方案结构程序运行时,首先根据用户配置文件自动生成词法分析器和语法分析器,数据帧识别器把接收到的数据帧进行词法分析,然后进行语法分析,最后得到分析结果。这样做的好处是,一旦底层应用设备协议发生变化,就可以适当更改用户配置文件,而不必把整个程序重新编译。

2.2 用户配置文件设计

用户配置文件是本文方案的基础所在,一个良好的配置文件设计,能够大大简便以后词法分析器和语法分析器的生成。由图1 可以看出,在设计时采用了2 个文件单独配置的方法:(1)底层设备协议的形式化描述,该配置文件主要用来自动生成词法分析器;(2)用户定义的语法规则,用来自动生成语法分析器。

协议的形式化描述实际上就是通过分析设备的协议定义,用正规式集的方式表现出来,以便进行词法分析。一条命令帧或响应帧的基本格式为:命令头_命令_参数_数据命令头:Gnn, AnnG:代表命令A:代表响应nn:命令或响应的序号命令:由两个字母表示的命令或响应的内容参数:参数表示了数据的来源、个数、大小、类型等数据:数据值,有的命令和响应没有数据部分_:代表一个或多个空格此类消息的形式化描述,即正规式集如下所示:digit [0-9]commandtype (a|g|p){digit}{digit}interrupt (p){digit}{digit}id [a-z][a-z0-9_ ]*integer {digit}{digit}*exp [Ee][+-]?{digit}+float ({digit}*”.“{digit}+({exp})?)|({digit}+”.“{digit}*({exp})?)token [a-z0-9_]+command (si)|(mn)|(sp)|(fg)|(fp)|(fs)| (ms)|(bf)| (bg)|(bd)|(bk)|(pm)|(sc)|(ac)datatype (int)|(flt)|(chr)|(der)bool (on)|(off)

value {integer}|{float}|{token}string语法规则定义是用户配置文件的主要部分,它既可以让用户定义一定的语法规则,还能够让用户决定在符合规则的情况下什么样的数据帧接受,什么样的数据帧抛弃,以及接受的数据帧哪一部分需要存储等一系列动作。该配置文件首先应该给出词法分析所能识别的协议关键字,这样用户就可以根据这些关键字和协议手册实现白己的配置。这些关键字的形式化描述上面己经给出。另外还应该包括己经提前定义的动作。本文在设计中采用了提前定义动作函数的方法。再就是规定用户配置条目的格式,具体设计包括两部分:

(1)语法规则条

语法规则条主要是用户根据具体需要写出程序应该能够识别的语法规则,该语法规则并不要求用户写出所有同该协议有关的条目,仅需要写出用户需要的规则即可。例如某用户仅需要识别返回数据的响应帧,就可以写成:commandtype_command_integer_parameter_data不必将并非返回数据的命令帧commandtype_ command__ _写出。

(2)相应动作项

相应动作项是发现符合用户定义的语法规则的数据帧后应该执行什么样的动作,常用的是存储,一般是数据项的存储,也可能是用户感兴趣的命令类型的存储等。例如,如果定义一个动作save(string key)可以把key 对应的实际数据值存到一个全局变量中,那么用户就可以在该分析器以外通过配置和调用从而获得感兴趣的数据。相应配置条目可以写成:commandtype_command_integer_parameter_data {save(data);}表示发现符合上述语法规则的数据帧就接受,并且存储data 数据项到全局变量。

2.3 词法分析器自动生成器

词法分析器的主要目的是读取用户的形式化描述,然后自动生成协议驱动表,即本文所说的词法分析器。词法分析器自动生成器的主要部分就是3 个主要算法,这3 个主要算法实现了从正规表达式到最小化确定有限自动机的一步步转换。最后生成的最小化确定有限自动机,既可以包括所有形式化描述的最小化确定有限自动机,也可以是针对每一个形式化描述的最小化确定有限自动机。本文采取的是后者。相应的数据结构如下:Sword[]单词数组,包含有3 个域:Name 域代表可识别的单词名称;States[]代表该单词状态数组;Trans[]是状态转移矩阵,Nstate=Trans[inChr] [curState]。

(1)从正规表达式到NFA

设计中用状态转换图来分别表示相应的NFA 或DFA,而在内存中的表示,则使用状态矩阵表示,即上面提到的Trans[]。在手工方式下,可以手工对每一类单词建立一张状态转换图,然后把所有的状态转换图合并成一张统一的状态图。在程序自动生成中,所有状态以及状态转换都需要保存,以便后继处理的使用。

(2)从NFA 到DFA

从不确定的有限自动机N 转换为一个等价的确定有限自动机M,可以用子集构造法完成[3]。M 的每个状态,对应于N 的一个状态的集合。其基本思想是:M 读入一个给定的输入串之后处于状态{x, y, z},当且仅当N 可能处在x, y, z 中任何一个状态,视N 选定哪个状态而定。让M 记住N 可能走的全部可能路线,并让M 同N平行地工作。M 的接收状态将是任何含有N 的接收状态的任何集合。

(3)DFA 的最小确定化

经过上述建立的DFA 并不是最优的,其状态数比必要的状态数可能要多,因此需要对这个DFA 进行最小化,其基本思想是:在一个状态集合中,还有不等价状态,就把不等价的状态分开,使一个集合中的状态等价。分开后,如果一个集合中的状态还有不等价的,就继续分开,直到每个分开的小集合中的状态都等价为止。

2.4 语法分析器自动生成器

有了以上的词法分析器自动生成器,就可以生成能够识别协议形式化描述中的所定义的单词。而这些单词,正是本文在用户语法规则条中所使用的。利用用户所定义的语法规则,生成相应的语法树。

由于该语法分析器是通过读取用户配置文件生成,因此首先要有一个小的词法分析器,能够识别文件中的单词,该词法分析器是按照文件中配置条的特殊字符进行分割,然后对比形式化描述文件中的定义,识别特定的和己经定义的单词符号。

(1)脚本文件识别器

脚本文件识别器主要是识别配置文件中所定义的节点关键词,如command, integer 等,即在语法配置文件中所出现的Sword[]中的name 域。该识别器也是一个词法分析器,只不过,它所要进行的动作是按照特定的分割字符,识别关键词。例如配置条目commandtype_command_integer_parameter_data {save(data);}中所出现的commandtype, command, integer, parameter,data 等。

首先是把形式化描述中的名称定义为关键字,然后通过词法分析的方法,识别语法配置脚本中的关键词,并且记下识别的顺序。

(2)语法树生成

考虑到本文所要进行的语法分析,是一种比较简单的对比分析,只要符合配置条目中所出现的语法配置条,就可以执行其后的动作。因为在设计中把配置条目的动作也作为一个单独的节点挂在语法树叶子节点的。这样一旦语法分析走到叶子节点,就可以认为是语法匹配,再进一步走到动作节点,去执行相应的语法动作。

2.5 数据帧识别器

当词法分析器和语法分析器都建立起来以后,就可以对数据帧进行分析识别。数据帧识别器接收数据帧,然后调用词法分析器识别单词,然后根据识别出的单词的顺序去查语法树,最后执行能够识别的语法的对应动作。

当系统取得所要识别的数据帧后,首先把它转换成字符串,然后存到字符缓冲区;词法分析器从缓冲区的头部开始进行状态匹配,如果出现不匹配的情况要进行字符回退,词法分析的结果是把所有的单词识别出来并按顺序存储。随后这些按顺序存储的单词查找语法树,并执行能够匹配的语法树的动作。其结构如图3 所示。

3 结束语

该系统如果底层协议发生变化,只需要在形式化描述文件中加入新的协议形式化描述,在用户语法配置文件中加入新的语法配置条。程序启动时,会自动生成相应的词法分析器和语法分析器,此时的词法分析器和语法分析器己经是不同于先前而是适合于现在底层协议的分析器,协议识别主程序就会调用该新生成的词法分析器和语法分析器分别进行词法分析和语法分析,从而进行相应的数据提取。此过程完全避免了应用程序的重新编译,而且,一般用户经过简单培训,也可以方便地对配置文件进行手工配置,解放了开发人员对整个应用程序的维护[4]。

本文所介绍的词法分析和语法分析的自动生成方法,在目前基于网络的应用程序开发中具有很大的意义(如可用于协议分析和协议转换等)。基于状态转换图的模式匹配方法具有一般匹配无可比拟的效率,可用于基于规则的网络入侵监测中等。

篇11:解析RIPv1和RIPv2路由协议特点

RIP路由协议在现实中已经很少使用了,它是一种距离矢量路由协议,

距离矢量路由协议的特点

1 定时发送路由更新:运行距离矢量路由协议的路由器每经过一个特定的时间周期就会发送更新信息。

2 邻居:邻居通常意味着共享相同的数据链路的路由器或者某种高层逻辑邻接关系。距离矢量路由协议向邻居发送更新信息,并依靠邻居再想它的邻居传递更新信息。

3 广播更新:运行距离矢量路由协议的路由器使用广播方式(255.255.255.255)发送更新信息。

4 全路由表更新:运行距离矢量路由协议的路由器发送的路由信息包含它的整个路由表。

RIP的发展历史:网关信息协议(GWINFO)------路由信息协议-------路由守护程序-------RIP-----RIPv2----RIPng

RIP的特点:

RIP是Routing Information Protocol (路由信息协议)的简称。它是一种相对简单的动态路由协议,但在实际使用中有着广泛的应用。RIP是一种基于D-V算法的路由协议,它通过UDP交换路由信息,每隔30秒向外发送一次更新报文。如果路由器经过180秒没有收到来自对端的路由更新报文,则将所有来自此路由器的路由信息标志为不可达,若在其后120 秒内仍未收到更新报文,就将该条路由从路由表中删除。

RIP 使用跳数(Hop Count)来衡量到达目的网络的距离,称为路由权(Routing Metric)。在RIP中,路由器到与它直接相连网络的跳数为0,通过一个路由器可达的网络的跳数为1,其余依此类推。为限制收敛时间,RIP规定metric取值0~15之间的整数,大于或等于16的跳数被定义为无穷大,即目的网络或主机不可达。(AD=120)

为提高性能,防止产生路由环路,RIP支持水平分割(Split Horizon)与路由中毒(Poison Reverse),并在路由中毒时采用触发更新(Triggered Update)。另外,RIP协议还允许引入其它路由协议所得到的路由,

RIP包括RIP-1和RIP-2两个版本,RIP-1 不支持变长子网掩码(VLSM),RIP-2 支持变长子网掩码(VLSM),同时RIP-2支持明文认证和 MD5 密文认证。

RIP-1使用广播发送报文,RIP-2有两种传送方式:广播方式和组播方式,缺省将采用组播发送报文,RIP-2的组播地址为224.0.0.9。组播发送报文的好处是在同一网络中那些没有运行RIP的网段可以避免接收RIP的广播报文;另外,组播发送报文还可以使运行RIP-1的网段避免错误地接收和处理RIP-2中带有子网掩码的路由。

路由器的基本配置

enable

configure terminal

hostname R1

enable password 12345

enable secret cisco

line console 0

logging synchronous

line vty 0 4

password 12345

login

端口基本配置

interface s/e...

ip address 192.168.1.1 255.255.255.0

no shutdown

clock rate 64000

RIP经常用到的命令

router rip

network 192.168.1.0

version {1 2}

常用的测试命令

ping

扩展ping

show ip

debug ip rip

show ip interface brief

篇12:协议离婚的材料准备及步骤解析

协议离婚的材料准备及步骤解析

协议离婚是我国法定的离婚方式之一,同时也是很多人选择的离婚方式。在协议离婚当中,夫妻双方必须就共同财产分割、子女抚养以及共同债务承担等问题做出协商,然后签订一份离婚协议书。你知道协议离婚手续怎么办吗?

双方通过协议方式离婚的,离婚登记按照初审——受理——审查——登记(发证)的程序办理。

协议离婚具体需要的'材料手续如下:

(一)、当事人提交证件和证明材料;

(二)、婚姻登记员查验相应证件和证明材料;

(三)、婚姻登记员向当事人讲明婚姻法关于登记离婚的条件;

(四)、婚姻登记员询问当事人的离婚意愿以及对离婚协议内容的意愿;

(五)、双方自愿离婚且对子女抚养、财产及债务处理等事项协商一致的,双方填写《申请离婚登记声明书》,并在监誓人面前签名;

(六)、夫妻双方亲自在离婚协议上签名;婚姻登记员作监誓人。协议书夫妻双方各一份,婚姻登记处存档一份; (七)、婚姻登记员对当事人提交的证件、申请离婚登记声明书、离婚协议书进行审查,符合离婚条件的,填写《离婚登记审查处理表》和离婚证;

(八)、颁发离婚证。

颁发离婚证应当在当事人双方均在场时按照下列步骤进行:

1、向当事人双方核实姓名、出生日期、离婚意愿;

2、告知当事人双方领取离婚证后的法律关系以及离婚后与子女的关系、应尽的义务;

3、见证当事人本人亲自在《离婚登记审查处理表》“当事人领证签名或按指纹”一栏中签名;当事人不会书写姓名的,应当按指纹。

4、在当事人的结婚证上加盖条型印章,其中注明“双方离婚,证件失效。××婚姻登记处”。注销后的结婚证退还当事人。

5、将离婚证分别颁发给离婚当事人双方,向双方宣布:取得离婚证,解除夫妻关系。

如果当事人无法就离婚事宜协商一致的话,那么就只能通过诉讼的方式离婚。此时需要一方向法院提交离婚起诉书,以启动离婚程序。在诉讼离婚当中,双方都想为自己争取更多的利益。

篇13:PS/2接口协议解析及应用

PS/2接口协议解析及应用

摘要:文中详细介绍了PS/2接口协议的内容、电气特性和标准键盘的第二套键盘扫描码集。给出了基于嵌入式系统的PS/2接口的软、硬件实现方法,并介绍了工控PC外接双键盘的解决方案。通过使用模拟开关CD4052巧妙地解决了工控PC外接双键盘的冲突问题。

关键词:PS/2接口;串行通讯;单片机;键盘;CD4052

1 PS/2接口标准的发展过程

随着计算机工业的发展,作为计算机最常用输入设备的键盘也日新月异。1981年IBM推出了IBM PC/XT键盘及其接口标准。该标准定义了83键,采用5脚DIN连接器和简单的'串行协议。实际上,第一套键盘扫描码集并没有主机到键盘的命令。为此,1984年IBM推出了IBM AT键盘接口标准。该标准定义了84~101键,采用5脚DIN连接器和双向串行通讯协议,此协议依照第二套键盘扫描码集设有8个主机到键盘的命令。到了1987年,IBM又推出了PS/2键盘接口标准。该标准仍旧定义了84~101键,但是采用6脚mini-DIN连接器,该连接器在封装上更小巧,仍然用双向串行通讯协议并且提供有可选择的第三套键盘扫描码集,同时支持17个主机到键盘的命令。现在,市面上的键盘都和PS/2及AT键盘兼容,只是功能不同而已。

2 PS/2接口硬件

2.1 物理连接器

一般,具有五脚连接器的键盘称之为AT键盘,而具有六脚mini-DIN连接器的键盘则称之为PS/2键盘。其实这两种连接器都只有四个脚有意义。它们分别是Clock(时钟脚)、Data?数据脚?、+5V(电源脚)和Ground(电源地)。在PS/2键盘与PC机的物理连接上只要保证这四根线一一对应就可以了。PS/2键盘靠PC的PS/2端口提供+5V电源,另外两个脚Clock(时钟脚)和Data?数据脚?都是集电极开路的,所以必须接大阻值的上拉电阻。它们平时保持高电平,有输出时才被拉到低电平,之后自动上浮到高电平。现在比较常用的连接器如图1所示。

2.2 电气特性

PS/2通讯协议是一种双向同步串行通讯协议。通讯的两端通过Clock(时钟脚)同步,并通过Data(数据脚)交换数据。任何一方如果想抑制另外一方通讯时,只需要把Clock(时钟脚)拉到低电平。如果是PC机和PS/2键盘间的通讯,则PC机必须做主机,也就是说,PC机可以抑制PS/2键盘发送数据,而PS/2键盘则不会抑制PC机发送数据。一般两设备间传输数据的最大时钟频率是33kHz,大多数PS/2设备工作在10~20kHz。推荐值在15kHz左右,也就是说,Clock(时钟脚)高、低电平的持续时间都为40μs。每一数据帧包含11~12个位,具体含义如表1所列。

表1 数据帧格式说明

1个起始位总是逻辑08个数据位(LSB)低位在前1个奇偶校验位

[1] [2] [3] [4] [5] [6]

篇14:软考网络管理员复习笔记第4章 协议属性

第4章 协议属性

一、OSI参考模型

应用层

表示层

会话层

传输层

网络层

数据链路层

物理层

二、全局协议分类

1、面向连接的协议:

windows size:在需要目标系统确认的传输的数据包数,

队列数据传送:对进入和发送的PDU指定序号,在目的地再按序号重排数据;

流控:确保发送的速率不超过目标接收的速率,通过为传输建立窗口尺寸实现;

错误控制:确保接收到的数据连续并无错,如有丢失或损失的PDU,则不发送ACK包,

备考资料

面向连接的协议有:ATM、TCP、Novell SPX、Apple Talk ATP;

2、非连接的协议

不包括连接设置和终止,没有流控和错误控制。

非连接的协议有:UDP、Apple Talk DDP、Novell IPX;

三、第2层:数据链路层

1、Ethernet/IEEE802.3

2、Token Ring/IEEE802.5

四、PPP
五、SDLC
六、Frame. Relay
七、ISDN
八、第3、4层:IP路由协议

1、IP

2、ICMP

3、TCP

4、UDP

仲裁协议第三人之解析

东软笔试题

软测笔试题

文化软实力论文

软笔书法教学计划

职场的软实力

软考网络管理员复习笔记 第6章 TCP/IP路由协议故障处理

东软新员工培训心得体会

可爱软妹个性签名

好听的软妹网名

《软交换网协议解析(共14篇).doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式

点击下载本文文档