分类: 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“是人肉分析出来的,不是运行代码测试出来的,如有错误,请不吝指正,谢谢。
chinaunix网友2011-03-06 14:24:38
很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com