2

重複の可能性:
ソケットから受信したストリームは単一の送信コマンドに制限されていますか?

注:この質問は非常に複雑であると思います(願わくば、皆さんのためではないので、ここで質問しますlol)。できるだけ単純で明確に説明するように最善を尽くしました。

私のアプリケーションでは、固定サイズのバッファでバイト配列を継続的に受信しています。

私が受け取っているこれらの一連のバイト配列は、「バイナリ」でシリアル化されています。

ただし、受信したバイト配列が固定サイズのバッファーよりも大きくなることがあるため、現在受信しているバイト配列をコンテナーに格納し、受信した残りのバイト配列を受信するために再度ループする必要があります。

私の質問は、受け取ったバイト配列のすべての「バッチ」を「連結」、「結合」、または「結合」して、単一のバイト配列を形成する方法です(コンテナ、場合によってはバイト配列のキューに格納されます)。それらを逆シリアル化しますか?

int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
    {
        // There might be more data, so store the data received so far.
        // If the buffer was not filled, I have to get the number of bytes received as Thorsten Dittmar was saying, before queuing it
        dataReceivedQueue.Enqueue(state.buffer);

        // Get the rest of the data.
        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
        new AsyncCallback(ReceiveCallback_onQuery), state);
    }
else
{
    // All the data has arrived; put it in response.
    response_onQueryHistory = ByteArrayToObject(functionThatCombinesBytes(dataReceivedQueue));

    // Signal that all bytes have been received.
    receiveDoneQuery.Set();
}

state.bufferは、データを受信するバッファーです。bufferはサイズ4096のバイト配列です。stateはStateObject型です。

ByteArrayToObject(byte [])は、受信したデータの逆シリアル化とオブジェクト形式への変換を処理します

functionThatCombinesBytes(Queue)この関数はバイトのキューを受け取り、すべてのバイトを1つのバイト配列に「結合」します

4

3 に答える 3

3

特定のサイズのバッファで呼び出しBeginReceiveているからといって、必ずしもバッファが完全にいっぱいになるとは限りません。したがって、キューに入れられたバッファの一部は実際には受信したデータで部分的にしかいっぱいにならず、残りはゼロの場合、実際にバッファに読み込まれたバイト数も格納されていないため、単純に連結すると、結合されたストリームがほぼ確実に破損します。また、毎回同じバッファを再利用しているように見えるため、すでに読み取ったデータを新しいデータで上書きするだけです。

したがって、をに置き換えて、次のようなものを使用することをお勧めしdataReceivedQueueますMemoryStream

if (bytesRead > 0)
    {
        // There might be more data, so store the data received so far.
        memoryStream.Write(state.buffer, 0, bytesRead);

        // Get the rest of the data.
        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
        new AsyncCallback(ReceiveCallback_onQuery), state);
    }
else
{
    // All the data has arrived; put it in response.
    response_onQueryHistory = ByteArrayToObject(memoryStream.ToArray());

    // Signal that all bytes have been received.
    receiveDoneQuery.Set();
}
于 2012-12-07T12:57:45.383 に答える
2

まず、dataReceivedQueueの型が独自の (またはQueueのオーバーライド)Enqueueメソッドを実装しない限り、呼び出しstate.bufferごとに書き換えられclient.BeginReceiveます。

MemoryStreamメンバーを単純に追加し、StateObjectバイトが来るとそれに追加できます。

state.rawData.Seek(0, SeekOrigin.End);
state.rawData.Write(state.buffer, 0, bytesRead);
于 2012-12-07T13:10:00.783 に答える
1

まず、バイト配列を格納するだけでなく、実際に有効な配列内のバイト数も格納する必要があります。たとえば、各受信でバッファが完全に満たされない場合があるため、バイト数が返さbytesReadれます(コード内)。

これがあれば、「バッチ」ごとに受信したバイト数を合計して、最終バッファのサイズを計算できます。

その後、ループ内でArray.Copy、「バッチ」を指定された長さで指定された位置にターゲット配列にコピーするために使用できます。

たとえば、これは次のようになります。

// Batch is a class that contains the batch byte buffer and the number of bytes valid
int destinationPos = 0;
byte[] destination = new byte[<number of bytes in total>];
foreach (Batch b in batches)
{
    Array.Copy(b.Bytes, 0, destination, destinationPos, b.ValidLength);
}
于 2012-12-07T12:56:11.753 に答える