当以 1024 字节为单位读取数据时,如何继续从接收大于 1024 字节的消息的套接字读取数据,直到没有剩余数据为止?我是否应该仅使用 BeginReceive 来读取数据包的长度前缀,然后在检索到该前缀后,使用 Receive() (在异步线程中)来读取数据包的其余部分?或者还有别的办法吗?
edit:
我认为 Jon Skeet 的链接有解决方案,但该代码有一些障碍。我使用的代码是:
public class StateObject
{
public Socket workSocket = null;
public const int BUFFER_SIZE = 1024;
public byte[] buffer = new byte[BUFFER_SIZE];
public StringBuilder sb = new StringBuilder();
}
public static void Read_Callback(IAsyncResult ar)
{
StateObject so = (StateObject) ar.AsyncState;
Socket s = so.workSocket;
int read = s.EndReceive(ar);
if (read > 0)
{
so.sb.Append(Encoding.ASCII.GetString(so.buffer, 0, read));
if (read == StateObject.BUFFER_SIZE)
{
s.BeginReceive(so.buffer, 0, StateObject.BUFFER_SIZE, 0,
new AyncCallback(Async_Send_Receive.Read_Callback), so);
return;
}
}
if (so.sb.Length > 0)
{
//All of the data has been read, so displays it to the console
string strContent;
strContent = so.sb.ToString();
Console.WriteLine(String.Format("Read {0} byte from socket" +
"data = {1} ", strContent.Length, strContent));
}
s.Close();
}
现在,这种更正后的方法在大多数情况下都可以正常工作,但在以下情况下会失败数据包的大小是缓冲区的倍数。这样做的原因是,如果缓冲区在读取时被填满,则假定有更多数据;但和以前一样的问题发生了。例如,2 字节缓冲区在 4 字节数据包上被填充两次,并假设有更多数据。然后它会阻塞,因为没有任何内容可供读取。问题是接收函数不知道数据包何时结束。
这让我想到了两种可能的解决方案:我可以有一个数据包结束定界符,或者我可以读取数据包标头以找到长度,然后准确接收该数量(正如我最初建议的那样)。
但这些都存在问题。我不喜欢使用分隔符的想法,因为用户可以以某种方式将其放入应用程序输入字符串中的数据包中,然后将其搞砸。对我来说这也显得有点草率。
长度标头听起来不错,但我计划使用协议缓冲区 - 我不知道数据的格式。有长度标头吗?它有多少字节?这是我自己实现的吗? ETC..
我应该怎么办?