VxWorks是美国Wind River公司推出的一款专门为实时系统设计开发的操作系统内核,为程序员提供了高效的实时多任务调度、中断管理,实时的系统资源以及实时的任务间通信。它是一种功能强大而且比较复杂的操作系统,包括进程管理、存储管理、设备管理、文件系统管理、网络协议及系统应用等部分。目前VxWorks应用已经十分广泛,从数码相机、路由器到B2隐形轰炸机、火星探路者,都有它的身影。在863某交通重大专项计划控制系统国产化研究项目中,分区控制计算机(DCC)和电机控制单元(MCU)也都采用了VxWorks操作系统。在现场测试过程中,我们发现基于TCP/IP网络协议传输的数据有时会出现粘包现象(即发送方发送的若干包数据传输到接收方时粘成一包)。针对这种情况,我们进行了专题研究与实验。本文重点分析了TCP/IP协议的粘包问题,并结合实验结果提出了解决该问题的对策和方法。
1、报文粘连问题的现象及分析
1.1 报文粘连问题的现象
TCP/IP报文粘连是指发送方发送的若干包数据,在接收方接收到时粘成一包,即后一包数据的头紧接着前一包数据的尾。由于报文长度与接收缓冲区长度有可能不成整倍数关系,所以粘连在一起的报文中有不完整的包。VxWorks操作系统会先将由网络传输来的数据放入系统接收缓冲区中,以备用户进程从中调用数据。此处假设接收方缓冲区长为L字节,L应有一定的长度,以保证至少可以存储一包数据。由于DCC和MCU之间需要传输不同种类的报文来进行数据交互,所以用户在程序中应为不同的报文分别设置不同的接收缓冲区来存放不同的报文数据。此处假设只有应答报文和状态报文两种,分别以用户缓冲区1和2来存储;长度应与用户层对应报文的长度相等,假设分别为m和n。粘包情况如图1所示。
图1 粘包情况示意图
1.2 报文粘连问题的分析
报文粘连既可能由发送方产生,也可能由接收方产生,还可能由进行数据传输的交换机产生。
(1) 发送方引起的报文粘连
由发送方引起的报文粘连是源于TCP协议本身。因为TCP协议为提高传输效率采用了Nagle算法(详见RFC896),发送方要等收集到1460字节的数据才会发送一包数据,或是等到发送缓冲区满后才会发送一包数据,这就造成了报文的粘连。
(2) 接收方引起的报文粘连
由接收方引起的报文粘连,往往是因为接收方进程没有及时处理数据造成的。接收方要先把收到的数据放入接收数据缓冲区,用户进程再从该缓冲区中读取数据。如果在下一包数据到达时前一包数据还未被用户进程取走,则新一包数据就接到前一包数据之后,而用户要根据事先设定好的缓冲区大小从系统接收缓冲区中读取数据,这就造成了一次取到了多包数据。
(3) 由交换机引起的报文粘连
由交换机引起的报文粘连,往往是因为由交换机相连的各个部件在一段时间内发送的报文数据太多,以至于超出了交换机的处理能力。这样,本来发送端分开发送的数据报文在交换机内部的缓冲区中粘连在一起。现在,在实验现场DCC等使用VxWorks操作系统的部件需要使用一个独立的端口进行程序下载,还要有一个独立的端口提供给SecureCRT软件以进行实时监控;同时DCC与MCU和中央控制系统的数据传输也要在同一台交换机中进行。这就有可能导致在某一段时间内数据量超过了交换机的处理能力。
1.3 文粘连对系统的影响
如果系统发生了报文粘连现象而不进行相应处理,则将导致整个系统无法正常运行。
如果用于传输数据的报文被粘连导致无法正常处理,则将使接收方无法进行运算,现场实时的数据无法获得,从而使标志位无法置位,程序无法继续进行。如果作为生命信号的报文被粘连导致无法正常处理,则将使接收方认为发送方出现故障;若此情况连续发生,则接收方将认为发送方死机,从而停机,以保证整个系统的安全。
2、报文粘连问题的解决方法
2.1 发送方的解决方法
对于由发送方引起的报文粘连,可以采用以下两种方法解决。
(1) 关闭Nagle算法
由于VxWorks系统支持Windows Sockets 1.1标准,可以将setsockopt函数中的level项设置为IPPROTO_TCP1,这样就可以关闭Nagle优化算法。
(2) 将Winsock kernel buffer设置为0
此方法只有在支持Windows Sockets 2.0标准的系统上才能使用(VxWorks不能支持),可在发送方为工控机、接收方为使用VxWorks操作系统的处理器的情况下使用。只需将setsockopt项中的level设为SOL_SOCKET,将SO_SNDBUF值设为0。
2.2 接收方的解决方法
对于由接收方引起的报文粘连,也有两种方法解决。
(1) 提高报文处理任务的优先级
使用VxWorks操作系统可以方便地设置任务的优先级。使用taskSpawn函数启动任务,其中priority的数值就是任务的优先级(从0~255,优先级依次降低)。使用此函数将处理报文任务的优先级设为比其他任务高,但是为了减小意外发生的可能,该值应小于100,因为taskSpawn的默认优先级为100。
(2) 将粘连在一起的报文进行分包处理
此方法是规定报文数据某一位的内容为该帧报文数据的总长度,接收方先提取出此内容,如果缓冲区中的数据长度大于等于该长度,则按该内容的长度从缓冲区中提取数据;如果长度不够则不提取数据,等到长度达到要求时再提取数据。这样即使出现报文粘连现象,应用程序也会将粘连在一起的数据进行分包处理,不会出现数据丢失无法识别报文ID的情况。下面通过一个具体例子进行详细说明。
在实验线上MCU发送给DCC的状态报文长度为84字节(报文ID为91H),应答报文长度为20字节(报文ID为81H),接收缓冲区为90字节。如果状态报文粘连在应答报文之后,则将使DCC无法收到完整的状态报文。这种情况连续发生3次之后,DCC将认为任务MCU发生故障,系统将停机,因而结果必然是错误的。如果将报文长度放在报文的第一位中,报文ID放在第二位中,则进行分包处理后就不会出现上述的诊断错误。处理过程如图2所示。
图2 分包处理过程
2.3 交换机的解决方法
对于由交换机引起的报文粘连,有3种解决方法:
(1) 使用有更强处理能力的交换机
可使用处理能力更强、拥有较大缓存空间的交换机。可是目前实验现场已经使用了某外国著名厂商的16口交换机,且该交换机有1MB的缓存空间,使用更高档的交换机无疑会使成本增高。
(2) 增加交换机数量
可将1台16口交换机的工作量交由2台8口交换机来完成,再将这两台交换机进行连接。这种方法可以明显降低一台交换机的数据处理负担,但会使系统的可靠性和安全性指标大幅度降级;而且随着以后实验设备的增加,不断连接新交换机的方法有可能使网络形成环路,这将造成网络瘫痪。所以,不建议使用此方法。
(3) 修改对交换机的配置
可通过修改相关参数将交换机数据传输方式设置为无等待传输,即在交换机得到数据后不放入内部缓冲区,而是直接交给接收方。这种方式在一定程度上可以避免粘包现象的发生,但当报文传输很紧密时也有继续产生粘包现象的可能。
3、结论
通过对发送方和接收方4种解决方法的现场实验,我们发现效果不尽相同。
① 在关闭Nagle算法的情况下,发现Nagle算法依然在使用。最终的结论是,这是Winsock的一个BUG,并且已经在微软的BUG目录中得到了证实,所以此方法无效。
② 将Winsock kernel buffer设置为0后粘包问题得到了解决,但传输速度明显降低。经测试,每秒大概只能传送5帧数据,这在VxWorks这种硬实时系统中是无法接受的。
③ 提高报文处理任务优先级的方法可以对报文粘连起到防治,但有可能产生一些不易发现的任务调度问题。
④ 分包处理的方法虽然不能防止粘连的发生,但是可以完全防止报文粘连对系统产生的影响。实践证明,使用分包处理的方法可以在高速数据传输的情况下保证传输的正确性,而且不会产生任何副作用,对处理速度的影响也很小,可以忽略不计。这种方法已经在实验现场使用了很长一段时间,运行情况良好。
参考文献
[1] Nagle J. Congestion Control in IP/TCP Internet works[S]. RFC896,1984.
[2] 陈智育,温彦军,陈琪.VxWorks程序开发实践[M].北京:人民邮电出版社,2004.
[3] 邝坚.Tornado/VxWorks入门与提高[M].北京:科学出版社,2004.
[4] WindRiver. VxWorks for PowerPC Architecture Reference 5.5,2003。