确定套接字流中的消息结束
本文关键字:消息 结束 套接字 | 更新日期: 2023-09-27 18:04:31
我有一个使用异步套接字连接的服务器和客户端的项目。
我想发送一个对象从服务器到客户端。不幸的是,我有一个问题,有时物体不能一次完全传输。因此,我需要一种方法来确定一个对象何时被完全传输。因此,我在传输的数据中添加了一个四字节头,以告知流将有多长。
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;
}
<<p> 解决方案/strong> 多亏了usr我已经把客户端的ReceiveCallbackCode中的bytesread部分改成了这个。现在似乎可以了。
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);
}
}
}
您没有使用EndReceive
(bytesRead
)的返回值。它表示接收了多少字节。
在bytesRead == 0
的情况下,你只是什么也不做,这可能不是一个正确的响应连接已经结束。
然后是这个不同步的忙循环:
while (state != null && state.tempBuffer.Length >= state.bufferSize);
这将为每个客户端连接消耗一个CPU核心。