我有一个客户端服务器应用程序,我最近对其进行了修改,以使在第一个完成之前在同一Socket上再次调用BeginRecieve。现在,第一个消息被完美地接收到了,但是在下一个消息中,标头的缓冲区(请参见下面的代码)充满了大的肥零,而不是我应该接收的数据。
public class Client
{
Socket sock;
Message message;
MessageHeader header;
byte[] headerBuffer = new byte[MessageHeader.HEADER_SIZE];
byte[] dataBuffer;
bool activeReceiver = false;
public delegate void DisconnectedHandler(Client c);
public event DisconnectedHandler Disconnected;
public delegate void DataReceivedHandler(Client c, Message m);
public event DataReceivedHandler DataReceived;
public Client(Socket sock)
{
this.sock = sock;
sock.BeginReceive(headerBuffer, 0, MessageHeader.HEADER_SIZE, SocketFlags.None, ReceiveCallback, null);
}
internal void Activate()
{
activeReceiver = true;
sock.BeginReceive(headerBuffer, 0, MessageHeader.HEADER_SIZE, SocketFlags.None, ReceiveCallback, null);
}
internal void ForceReceive()
{
if (!activeReceiver)
{
sock.BeginReceive(headerBuffer, 0, MessageHeader.HEADER_SIZE, SocketFlags.None, ReceiveCallback, null);
}
}
private void ReceiveCallback(IAsyncResult result)
{
int received;
try
{
received = sock.EndReceive(result);
if (received != MessageHeader.HEADER_SIZE && Disconnected != null)
{
Disconnected(this);
return;
}
else if (received == MessageHeader.HEADER_SIZE)
{
header = new MessageHeader(headerBuffer);
if (header.size > 0)
{
dataBuffer = new byte[header.size];
sock.Receive(dataBuffer);
message = new Message(header, dataBuffer);
if (DataReceived != null)
{
DataReceived(this, message);
}
}
message = null;
headerBuffer = new byte[MessageHeader.HEADER_SIZE];
dataBuffer = null;
if (sock != null && activeReceiver)
{
sock.BeginReceive(headerBuffer, 0, MessageHeader.HEADER_SIZE, SocketFlags.None, ReceiveCallback, null);
}
}
}
catch (SocketException sex)
{
switch (sex.SocketErrorCode)
{
case SocketError.ConnectionAborted:
case SocketError.ConnectionReset:
if (Disconnected != null)
{
Disconnected(this);
}
break;
}
}
}
MessageHeader是一个简单的小类:
public class MessageHeader
{
public static int HEADER_SIZE = 12;
public int type, size, source;
public MessageHeader(int type, int size, int source)
{
this.type = type;
this.size = size;
this.source = source;
}
public MessageHeader(byte[] raw)
{
if (raw.Length != HEADER_SIZE)
{
type = -1;
size = -1;
source = -1;
}
type = BitConverter.ToInt32(raw, 0);
size = BitConverter.ToInt32(raw, 4);
source = BitConverter.ToInt32(raw, 8);
}
public byte[] toBytes()
{
byte[] bytes = new byte[HEADER_SIZE];
BitConverter.GetBytes(type).CopyTo(bytes, 0);
BitConverter.GetBytes(size).CopyTo(bytes, 4);
BitConverter.GetBytes(source).CopyTo(bytes, 8);
return bytes;
}
}
这种方法的工作方式(并且可以完美地工作)是activeReceiver无关紧要,在每个回调的结尾都会调用BeginReceive。现在,新的修改是activeReceiver变量以及ForceReceive和Activate方法。直到可以安全地将客户端放回自动调用BeginReceive的模式之前,在由DataReceived委托处理数据之后,从外部对其调用ForceReceive()。当可以安全地重新输入原始行为时,将调用Activate而不是ForceReceive,然后从此恢复到原始行为。在我唯一可能的测试案例中,此阶段从未达到。服务器与客户端之间的消息交换正常进行了一次,然后当服务器不响应下一条消息时,客户端将锁定。
请注意,当我得到0-es(这是来自客户端的第二条消息)时,我们确实进入了在headerBuffer中接收到正确字节数的情况,只有12个都是0-es。
更新:因此,我使用了一个非常麻烦的解决方案来解决它,这在内存方面是浪费的,但是我想做一个更优雅,更有效的内存解决方案,所以如果有人发现了这一点,我仍然会很高兴看到这个谜题解决了。