Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2243403
  • 博文数量: 230
  • 博客积分: 9346
  • 博客等级: 中将
  • 技术积分: 3418
  • 用 户 组: 普通用户
  • 注册时间: 2006-01-26 01:58
文章分类

全部博文(230)

文章存档

2015年(30)

2014年(7)

2013年(12)

2012年(2)

2011年(3)

2010年(42)

2009年(9)

2008年(15)

2007年(74)

2006年(36)

分类: LINUX

2015-04-09 12:19:49

原文地址:别用TCP的紧急数据 作者:raise_sail

公司分布式系统的通信组件实在有点看不下去了,有自己的想法,动动手吧,有个原型也好与人PK。

想当然地希望使用TCP紧急数据处理作为“消息”的异常中止标志,心想这个简单,加了EPOLLPRI后,一直表现正常的epoll_wait()突然陷入了看似万劫不复的等待当中。修改一下代码后,发现了另一个问题,明明是用send(MSG_OOB)发送的带外数据,却出现在正常的字节流中,可是没有设置SO_OOBINLINE啊,神秘事件。

费几个周折,最终确定我的代码是OK的,稍微修改一下UNP的例子也可以重现这个问题:让sender只发送MSG_OOB数据,而接收者不读归紧急数据,只读取正常的字节流。不一会儿,接收程序就从正常字节流中读出东西了。按预想的情况,接收者应该永远阻塞才是。

开始以为是TCP receiver side的内核代码出了问题,检查一下更新tcp_sock->urg_data/urg_seq的代码没有什么问题啊,并且2.6.32和2.6.38-rc7都有这个问题!抓包看看吧,有些数据包有16384字节长。看来发送消息时就有“问题”,看tcp_sendmsg()吧。果然这里是有可能出现情况的。心想,这是个bug吧!心中窃喜,让俺抓到TCP stack的小辫子了?

怎么fix呢?查查以前下载RFC全集,根本就没要求带外数据一定不能出现字节流中。想了想,改这个真是有些复杂的,发送端需要修改不说,连滑动窗口的行为恐怕都得动,不然,接收端可能还得缓冲一堆紧急指针。仔细想了想,这个劳什子的TCP紧急数据其实就是个不中用的货色:

1、最直观的缺点:名为带外数据,其实不带外,这也就罢了。数据长度只有一个字节,作用实在有限。

2、带外数据在TCP头内的偏移只有16bit长,而现代TCP连接大量使用的window scaling选项,这样滑动窗口的容量大大超出了16 bits能表示的范围。因此很可能在接收端还没有知晓前一个带外数据的时候,后一个段已经把紧急指针写掉了。这样,前一个紧急数据就被丢掉了。接收端的应用程序可能根本就不知晓。

3、Linux的TCP实现,如果两个紧急数据挨的太近,就引起上面的我提到的bug。

后来发邮件问了问netdev邮件列表上的达人,John回复说,参考一下RFC6093吧,一看,这个RFC还挺新鲜,2011-01, TCP的紧急数据已经是废弃的功能了。不建议新的应用程序使用,只为旧程序兼容而存在。即使是使用,也建议使用打开SO_OOBINLINE。可是,我要说,打开这个选项也没有什么帮助,因为这个选项只对接收端有作用,tcp_sendmsg()还是可能出现上述(3)的问题。TCP的RFC和实现代码都好复杂啊,对于它,很有些积重难返的感觉。也许在许多场合,SCTP是个更好的选择吧。

一句话,别用的TCP的紧急数据。

阅读(3398) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~