我有一个项目,服务器和客户端使用异步套接字连接。
我想将一个对象从服务器传输到客户端。不幸的是,我遇到了问题,有时候这个对象并没有一次完全传输。因此,我需要一种方法来确定对象何时完全传输。所以我在发送的数据中添加了一个四字节的磁头,告诉它将有多长时间。
Server
private void Send(Socket handler, Packet packet)
{
byte[] byteData = ByteHelper.Serialize(packet).Data;
byte[] byteDataLength = BitConverter.GetBytes(byteData.Length);
byte[] transmissionData = new byte[byteDataLength.Length + byteData.Length];
byteDataLength.CopyTo(transmissionData, 0);
byteData.CopyTo(transmissionData, byteDataLength.Length);
if (debug)
{
Status = "Sending "+packet.Type+"-packet to client.";
}
try
{
handler.BeginSend(transmissionData, 0, transmissionData.Length, 0, new AsyncCallback(SendCallback), handler);
}
catch (Exception ex)
{
Status = "[EXCEPTION]" + ex.Message.ToString();
}
}
客户端接收流并评估前四个字节以创建具有正确大小的StateObject。但我觉得这不是解决问题的好方法。有更好的方法吗?
Client
private void ReceiveCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
try
{
Socket client = state.workSocket;
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
do
{
state = AdjustState(state);
if (state != null)
{
if (state.buffer.Length == state.bufferSize)
{
ProcessPacket(state);
receiveDone.Set();
}
}
else
{
receiveDone.Set();
}
}
while (state != null && state.tempBuffer.Length >= state.bufferSize);
if (state != null)
{
client.BeginReceive(state.tempBuffer, 0, state.tempBuffer.Length, 0, new AsyncCallback(ReceiveCallback), state);
}
}
}
catch (Exception ex)
{
MessageBox.Show("ReceiveCallback: " + ex.ToString(), "Client-Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private static StateObject AdjustState(StateObject state)
{
StateObject tempState = state;
if (tempState.tempBuffer.Length >= 4)
{
byte[] sizeBytes = tempState.tempBuffer.Take(4).ToArray();
int bufferSize = BitConverter.ToInt32(sizeBytes, 0);
if (bufferSize == 0)
{
return null;
}
byte[] temp = tempState.tempBuffer.Skip(4).ToArray();
Socket tempSocket = tempState.workSocket;
tempState = new StateObject(bufferSize);
tempState.BufferSet();
if (temp.Length >= bufferSize)
{
tempState.buffer = temp.Take(bufferSize).ToArray();
tempState.tempBuffer = temp.Skip(bufferSize).ToArray();
}
tempState.workSocket = tempSocket;
}
return tempState;
}
解决方案
感谢 usr 我已将客户端的ReceiveCallbackCode中的bytesRead-Part更改为此。它似乎现在有效。
if (bytesRead > 0)
{
if (!state.bufferSet)
{
state = AdjustState(state);
client.BeginReceive(state.buffer, 0, state.bufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{
if (state.buffer.Length == state.bufferSize)
{
ProcessPacket(state);
receiveDone.Set();
}
else
{
client.BeginReceive(state.buffer, state.buffer.Length, state.bufferSize - state.buffer.Length, 0, new AsyncCallback(ReceiveCallback), state);
}
}
}
答案 0 :(得分:2)
您没有使用EndReceive
(bytesRead
)的返回值。它表示收到了多少字节。
如果bytesRead == 0
你只是做了什么,这可能不是对已经结束的连接的正确回应。
然后,存在这种不同步的忙循环:
while (state != null && state.tempBuffer.Length >= state.bufferSize);
这将为每个客户端连接刻录一个CPU核心。必须以不同的方式解决这个问题。