D 从具有范围的碎片字节流读取数据包?
我相信我知道一些范围,但我不知道何时何地使用它们,或者如何使用。我无法“获取”范围。考虑这个例子:D 从具有范围的碎片字节流读取数据包?,d,range,D,Range,我相信我知道一些范围,但我不知道何时何地使用它们,或者如何使用。我无法“获取”范围。考虑这个例子: 假设我们有一个无法控制的网络处理程序,它在某个线程中调用回调函数,只要有一些新数据: void receivedData(ubyte[] data) 此数据流包含具有布局的数据包 { ushort size; ubyte[size] body; } 但是,网络处理程序不知道这一点,因此对dataReceived()的调用可能包含一个或两个部分数据包、一个或多个完整数据包或它们
假设我们有一个无法控制的网络处理程序,它在某个线程中调用回调函数,只要有一些新数据:
void receivedData(ubyte[] data)
此数据流包含具有布局的数据包
{
ushort size;
ubyte[size] body;
}
但是,网络处理程序不知道这一点,因此对dataReceived()
的调用可能包含一个或两个部分数据包、一个或多个完整数据包或它们的组合。为简单起见,假设不存在损坏的数据包,并且当连接关闭时,我们将收到data.length==0
我们现在想要的是一些漂亮的d代码,将所有这些混乱转化为对
void receivedPacket(ubyte[] body)
我当然可以想到用“暴力”的方式来实现这一点。但这也许是我困惑的地方:射程能在其中发挥作用吗?我们能把receivedData()
归纳成一个好的范围吗?怎么用?或者这不是你会使用范围的那种问题?为什么不呢
(如果使用范围更有意义,请随意重新定义示例。)我要做的是
ubyte[1024] buffer=void;//temp buffer set the size as needed...
ushort filledPart;//length of the part of the buffer containing partial packet
union{ushort nextPacketLength=0;ubyte[2] packetLengtharr;}//length of the next packet
void receivedData(ubyte[] data){
if(!data.length)return;
if(nextPacketLength){
dataPart = min(nextPacketLength-filledPart.length,data.length);
buffer[filledPart..nextPacketLength] = data[0..dataPart];
filledPart += dataPart;
if(filledPart == nextPacketLength){
receivedPacket(buffer[0..nextPacketLength]);//the call
filledPart=nextPacketLength=0;//reset state
receivedData(datadataPart..$]);//recurse
}
} else{
packetLengtharr[]=data[0..2];//read length of next packet
if(nextPacketLength<data.length){//full paket in data -> avoid unnecessary copies
receivedPacket(data[2..2+nextPacketLength]);
receivedData(data[2+nextPacketLength..$]);//recurse
}else
receivedData(data[2..$]);//recurse to use the copy code above
}
}
ubyte[1024]buffer=void//临时缓冲区根据需要设置大小。。。
ushort填充部分//包含部分数据包的缓冲区部分的长度
联合{ushort nextPacketLength=0;ubyte[2]packetLengtharr;}//下一个数据包的长度
无效接收数据(ubyte[]数据){
如果(!data.length)返回;
如果(下一个包长度){
dataPart=min(下一个包长度filledPart.length,data.length);
缓冲区[Filled Part..NextPackageLength]=数据[0..dataPart];
filledPart+=dataPart;
如果(填充部分==下一个包长度){
receivedPacket(缓冲区[0..nextPacketLength]);//调用
filledPart=nextPacketLength=0;//重置状态
receivedData(datapart..$]);//递归
}
}否则{
packetLengtharr[]=数据[0..2];//读取下一个数据包的长度
如果(下一个包装长度)避免不必要的副本
接收数据包(数据[2..2+下一个数据包长度]);
接收数据(数据[2+nextPackageLength..$]);//递归
}否则
receivedData(数据[2..$]);//递归以使用上面的复制代码
}
}
它是递归的,有3种可能的路径:
数据
为空->无操作nextPacketLength
设置为一个值!=0->将尽可能多的数据复制到缓冲区中,如果数据包已完成,则调用回调并重置filledPart
和nextPacketLength
并与剩余的数据一起递归
当数据只包含长度的第一个字节时,仍然只有一个bug,但我会让你知道(我现在懒得这么做)谢谢你的回答!它解决了问题,但它使用范围吗?不管怎样,我觉得这是正确的解决方案。