您确实需要详细说明如何设置套接字(是 TCP 还是 UDP?)
假设它是一个 TCP 套接字,那么您的客户端似乎依赖于每个接收调用,它们返回的字节数与服务器Send()
调用发送的字节数相同。然而,情况并非如此,如果在客户端上仅收到部分消息,或者一次收到多条消息,则很可能是您的问题的原因。
例如,服务器可能会在一次调用中发送一条 90 字节的消息,但您的客户端可能会以一个 90 字节的接收、或两个 45 字节的块、甚至 90 x 1 字节的块或介于两者之间的任何方式接收它。服务器发送的多条消息在客户端接收时也可能部分组合。例如,可以在一个 180 字节的块中接收两个 90 字节的消息,或者一个 150 字节和一个 30 字节的块等。
因此,您需要为您的消息提供某种框架,以便当客户端接收到数据流时,它可以可靠地重建为单独的消息。
最基本的成帧机制是在每条发送的消息前加上一个固定长度的字段来指示消息的大小。如果您可以保证您的消息永远不会超过 255 个字节,那么您可能能够摆脱单个字节,这将简化接收代码。
在客户端,您首先需要接收长度前缀,然后从套接字读取那么多字节来构造消息数据。如果您收到的字节数少于所需的字节数,您的接收代码必须等待更多数据(在最终收到时将其附加到部分接收的消息中),直到它有完整的消息。
一旦收到完整的消息,就可以按您当前的方式处理它。
不幸的是,我不了解 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;
}