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
    并与剩余的
    数据一起递归

  • nextPacketLength==0读取数据包长度(此处为union),如果完整数据包可用,则调用回调,然后与其余数据一起递归


  • 当数据只包含长度的第一个字节时,仍然只有一个bug,但我会让你知道(我现在懒得这么做)

    谢谢你的回答!它解决了问题,但它使用范围吗?不管怎样,我觉得这是正确的解决方案。