2

範囲はある程度知っていると思いますが、いつ、どこで、どのように使用するかについては、まったくわかりません。範囲を「取得」できません。次の例を検討してください。


新しいデータがあるたびに、何らかのスレッドでコールバック関数を呼び出す、制御できないネットワーク ハンドラーがあるとします。

void receivedData(ubyte[] data)

このデータ ストリームには、レイアウトのパケットが含まれています。

{
    ushort size;
    ubyte[size] body;
}

ただし、ネットワーク ハンドラーはこれを認識しないため、 への呼び出しにdataReceived()は、1 つまたは 2 つの部分的なパケット、1 つまたは複数の完全なパケット、またはそれらの組み合わせが含まれる場合があります。data.length == 0簡単にするために、破損したパケットはなく、接続が閉じられたときに を受け取ると仮定しましょう。

私たちが今求めているのは、このすべての混乱を適切な呼び出しに変える美しい D コードです。

void receivedPacket(ubyte[] body)

これを達成するための「ブルートフォース」の方法は確かに考えられます。しかし、ここでおそらく私の混乱が生じます。範囲はこれで役割を果たすことができますか? receivedData()素敵な範囲で締めくくることができますか?どのように?それとも、これは範囲を使用するような問題ではありませんか? なぜだめですか?

(範囲を使用する方が理にかなっている場合は、自由に例を再定義してください。)

4

1 に答える 1

2

私がすることは

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
    }
}

それは3つの可能なパスで再帰的です:

  1. data空です->アクションなし

  2. nextPacketLengthは値に設定されます!= 0->できるだけ多くのデータをバッファにコピーし、パケットが完了したら、コールバックを呼び出してリセットfilledPartnextPacketLength、残りの部分で繰り返しますdata

  3. nextPacketLength == 0パケットの長さを読み取り(ここではユニオンを使用)、完全なパケットが使用可能な場合はコールバックを呼び出し、残りのデータで再帰します

データが長さの最初のバイトしか保持していない場合、まだ1つのバグしかありませんが、それを理解させます(そして、私は今それを行うのが面倒です)

于 2012-11-21T12:49:50.453 に答える