Chinaunix首页 | 论坛 | 博客
  • 博客访问: 330956
  • 博文数量: 100
  • 博客积分: 2620
  • 博客等级: 少校
  • 技术积分: 920
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-16 02:50
文章分类

全部博文(100)

文章存档

2011年(5)

2010年(12)

2009年(83)

分类: C/C++

2011-02-19 15:33:53

       说到Circular Buffer(简称CB),一个不能避免的问题就是跨越边界的处理。从CB中读取的时候,如果遇到最后的边界,可能需要读取两次才能读够自己需要的数据。另外一种方法就是每次读取之后都把剩余的数据移动到头上去,但是这已经不是真正的CB了。

       写入到CB中时,存在同样的问题,比如现在的缓冲区如下:

|   x(B)  |   数据  | y(B) |

h       数据头    数据尾    t

      当往这样的CB中写入Z字节(y < Z < x + y)时,要么,分两次拷贝进来;如果是上层直接取“数据尾"的指针放到socket的read函数中取,那么字节数最多只能填y,所以要写入Z自己,上层得调用多次read系统调用,也是费啊。

     在Ascent中,CB在遇到上面的问题时,通过比较x和y的大小,返回较大的空间对应的指针(h或者"数据尾")。相当于浪费了y字节空间(x>y)时,即在这种情况下(x>y),数据就不会写到尾部去了,都是些到头部。 以后读取的时候,根据实际需要读取的字节数,可能发生两次拷贝操作。

    题目所说的bug,就是发生在读取并进行处理的时候,比如

void AuthSocket::HandleChallenge()
{
 // No header
 if(GetReadBuffer().GetContiguiousBytes() < 4)
  return; 

  . . . . .

}

    此处对CB中的数据要求是至少有联系的4字节才继续处理,加上上述情况发生了(x>y),y部分空出来不能再得到利用,而新的数据来都是放到了头部(x部分),当x部分被填满以后,就没有空间写新数据了,此时需要等待上层从"数据头"开始将数据读走。同时,众所周知,网络上TCP数据包是流式的,而且TCP怎么组织我们上层的数据包也是不可控制的。杯具就发生在,下一个包P的钱N个字节(N<4)粘在了上一个包后面,同时这个数据被我们正好读到了CB中,并上面的缓冲区的情况,当下一个包进来的时候(包含了P的后续数据)就只能放到头部(x部分),P数据包就被分开存放到了两个地方。此时,上层通过"数据头"不断的读取数据包,知道处理完最后一个完整的包,此时碰到了P包的前N个字节,但是N<4,这个函数进不去,后面的数据得不到处理,卡住了!欲知后事如何,请自行分解!

    所以,这个地方的条件判断应该是有问题的,在极端情况下还是会存在bug。个人还是更喜欢mangos里面的CB,通过分配double size来避免跨界问题。

  这个“bug“是人肉分析出来的,不是运行代码测试出来的,如有错误,请不吝指正,谢谢。

 

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

chinaunix网友2011-03-06 14:24:38

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com