我正在维护一个c#系统,其部分工作是从随机客户端接收tcp消息(使用socket.recv())。我们确实有一个消息协议,因此外部开发人员可以填充格式良好的消息。
消息格式如下:
{ public data(fixed length):private data(variable length) }
要接收消息,我们需要在此消息中使用私有数据长度字段,但是需要有人发送可能填充了错误的长度数字的消息。我怎样才能满足这个需求?
下面是我的代码:
public static int ReceiveMessage(int totalByteNumber, Socket socket, byte[] recvBuffer)
{
try
{
int offset = 0;
do
{
try
{
int num = socket.Receive(recvBuffer, offset, totalByteNumber - offset, SocketFlags.None);
if (num == 0)
{
throw new ApplicationException();
}
offset += num;
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.IOPending || ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
Thread.Sleep(30);
else if (ex.SocketErrorCode == SocketError.WouldBlock)
{
socket.Blocking = true;
Thread.Sleep(30);
}
else
{
LogManager.WriteError("Origin IP:" + (object) ((IPEndPoint) socket.RemoteEndPoint).Address);
throw ex;
}
}
}
while (offset < totalByteNumber);
return offset;
}
finally
{
SocketUtility.LogMessage("Recv", recvBuffer, socket);
}
}
不能容纳格式不正确的消息,至少不可靠。TCP不维护消息边界,因此您无法知道发送给您的消息有多长。
在实践中,如果您通常有短请求,并且请求者在一个send系统调用中发送整个请求,则每个接收方很可能只返回一条请求消息,但这并不可靠。例如,如果请求者连续向您发送两个请求,那么它们可能会在您的流程被调度之前合并,以便在单个接收调用中将两个请求返回给您。
你的选择:
- 消息中的长度字段,告诉您期望的长度(大多数二进制协议都以这种方式工作)
- 消息中的一些标志模式(空字节,或空文本行,或其他);基于文本的协议(如HTTP)通常以这种方式工作)
- 文件结束(即呼叫者可以发送请求,然后调用
socket.Shutdown(Send);
,你会得到EOF,知道这是所有的期望;显然这是一次性交易)