ソケットをどのように設定しているかについて、より詳細な情報を提供する必要があります (それは TCP ですか、それとも UDP ですか?)。
それが TCP ソケットであると仮定すると、クライアントは、サーバーのSend()
呼び出しによって送信されたのと同じバイト数を返す各受信呼び出しに依存しているように見えます。ただし、これは当てはまりません。メッセージがクライアントで部分的にしか受信されない場合、または複数のメッセージが一度に受信される場合は、問題の原因となる可能性があります。
たとえば、サーバーは 1 回の呼び出しで 90 バイトのメッセージを送信する場合がありますが、クライアントは 1 回の 90 バイトの受信、または 2 つの 45 バイトのチャンク、さらには 90 x 1 バイトのチャンク、またはその間の任意の受信で受信する場合があります。サーバーによって送信された複数のメッセージは、クライアントによって受信されるときに部分的に結合される場合もあります。たとえば、2 つの 90 バイトのメッセージが 1 つの 180 バイトのチャンク、または 150 バイトと 30 バイトのチャンクなどで受信される場合があります。
したがって、データのストリームがクライアントによって受信されたときに、個々のメッセージに確実に再構築できるように、メッセージに何らかのフレーミングを提供する必要があります。
最も基本的なフレーミング メカニズムは、送信される各メッセージの前に、メッセージ サイズを示す固定長フィールドを付けることです。メッセージの長さが 255 バイトを超えないことを保証できる場合は、1 バイトで済む可能性があります。これにより、受信コードが簡素化されます。
クライアント側では、最初に長さのプレフィックスを受け取り、ソケットからそのバイト数まで読み取ってメッセージ データを構築する必要があります。受信したバイト数が必要なバイト数よりも少ない場合、受信コードは、完全なメッセージが得られるまで、追加のデータを待機する必要があります (最終的に受信されたときに、部分的に受信されたメッセージに追加されます)。
完全なメッセージが受信されると、現在のように処理できます。
残念ながら私は ActionScript を知らないので、クライアント側のコードの例を示すことはできませんが、C# でサーバーとクライアントのフレーミングを記述する方法を次に示します。
サーバ側:
public void SendMessage(string message)
{
var data = Encoding.UTF8.GetBytes(message);
if (data.Length > byte.MaxValue) throw new Exception("Data exceeds maximum size");
var bufferList = new[]
{
new ArraySegment<byte>(new[] {(byte) data.Length}),
new ArraySegment<byte>(data)
};
ClientSocket.Send(bufferList);
}
クライアント側:
public string ReadMessage()
{
var header = new byte[1];
// Read the header indicating the data length
var bytesRead = ServerSocket.Receive(header);
if (bytesRead > 0)
{
var dataLength = header[0];
// If the message size is zero, return an empty string
if (dataLength == 0) return string.Empty;
var buffer = new byte[dataLength];
var position = 0;
while ((bytesRead = ServerSocket.Receive(buffer, position, buffer.Length - position, SocketFlags.None)) > 0)
{
// Advance the position by the number of bytes read
position += bytesRead;
// If there's still more data to read before we have a full message, call Receive again
if (position < buffer.Length) continue;
// We have a complete message - return it.
return Encoding.UTF8.GetString(buffer);
}
}
// If Receive returns 0, the socket has been closed, so return null to indicate this.
return null;
}