Async TCP Server - doradztwo w zakresie ramkowania wiadomości

Mam asynchroniczny serwer gniazd TCP w C #, który stworzyłem za pomocą wrapperów TcpListener / TcpClient dla Socket. Jestem całkiem nowy w sieci, więc nie wiedziałem, jak TCP traktuje przesyłane dane i jak nie zachowuje granic wiadomości. Po krótkich badaniach sądzę, że wymyśliłem solidne rozwiązanie, ale zastanawiam się, czy ktoś ma dla mnie więcej porad.

Obecnie przesyłane przeze mnie dane są bajtem [] serializowanego obiektu klasy przy użyciu protobuf (biblioteki wymiany danych Google)https://code.google.com/p/protobuf/

Po serializacji moich danych i przed wysłaniem zdecydowałem się dołączyć 4 bajty Int32 na początku tablicy bajtów. Mój pomysł polega na tym, że gdy pakiet zostanie wysłany na serwer, przeanalizuje Int32, a następnie poczeka, aż otrzyma tę liczbę bajtów, zanim zrobi cokolwiek z danymi, inaczej po prostu ponownie wywoła BeginRead.

Oto kod, przez który przechodzi, zanim napiszę dane, i wygląda na to, że działa dobrze, ale jestem otwarty na wszelkie sugestie dotyczące wydajności:

public byte[] PackByteArrayForSending(byte[] data)
{
    // [0-3] Packet Length 
    // [3-*] original data

    // Get Int32 of the packet length
    byte[] packetLength = BitConverter.GetBytes(data.Length);
    // Allocate a new byte[] destination array the size of the original data length plus the packet length array size
    byte[] dest = new byte[packetLength.Length + data.Length];

    // Copy the packetLength array to the dest array
    Buffer.BlockCopy(packetLength, 0, dest, 0, packetLength.Length);
    // Copy the data array to the dest array
    Buffer.BlockCopy(data, 0, dest, packetLength.Length, data.Length);

    return dest;
}

Jestem trochę utknięty na końcu serwera. Czytam zmienną packetLength, używając Buffer.BlockCopy, aby skopiować pierwsze 4 bajty, a następnie BitConverter.ToInt32, aby odczytać długość, jaką powinienem uzyskać. Nie jestem pewien, czy powinienem stale odczytywać dane przychodzące do obiektu Stream specyficznego dla klienta, czy po prostu użyć pętli while. Oto przykład kodu, który mam na końcu serwera:

NetworkStream networkStream = client.NetworkStream;
int bytesRead = networkStream.EndRead(ar);

if (bytesRead == 0)
{
  Console.WriteLine("Got 0 bytes from {0}, marking as OFFLINE.", client.User.Username);
  RemoveClient(client);
}

Console.WriteLine("Received {0} bytes.", bytesRead);

// Allocate a new byte array the size of the data that needs to be deseralized.
byte[] data = new byte[bytesRead];

// Copy the byte array into the toDeserialize buffer
Buffer.BlockCopy(
  client.Buffer,
  0,
  data,
  0,
  bytesRead);

// Read the first Int32 tp get the packet length and then use the byte[4] to get the packetLength
byte[] packetLengthBytes = new byte[4];
Buffer.BlockCopy(
  data,
  0,
  packetLengthBytes,
  0,
  packetLengthBytes.Length);

int packetLength = BitConverter.ToInt32(packetLengthBytes, 0);

// Now what do you recommend?

// If not all data is received, call 
// networkStream.BeginRead(client.Buffer, 0, client.Buffer.Length, ReadCallback, client);
// and preserve the initial data in the client object

Dziękuję za poświęcony czas i radę, czekam na więcej informacji na ten temat.

questionAnswers(1)

yourAnswerToTheQuestion