这是我的代码:
private void OnReceive(IAsyncResult result)
{
NetStateObject state = (NetStateObject)result.AsyncState;
Socket client = state.Socket;
int size = client.EndReceive(result);
byte[] data = state.Buffer;
object data = null;
using (MemoryStream stream = new MemoryStream(data))
{
BinaryFormatter formatter = new BinaryFormatter();
data = formatter.Deserialize(stream);
}
//todo: something with data
client.BeginReceive(
state.Buffer,
0,
NetStateObject.BUFFER_SIZE,
SocketFlags.None,
OnReceive,
state
);
}
state.Buffer的最大大小为NetStateObject.BUFFER_SIZE(1024)。首先,这太大还是太小?其次,如果我发送大于那个的东西,我的反序列化会搞砸,因为它试图反序列化的对象没有所有信息(因为并非所有数据都被发送)。在尝试构建数据并对其执行某些操作之前,如何确保已收到所有数据?
已完成的工作代码
private void OnReceive(IAsyncResult result)
{
NetStateObject state = (NetStateObject)result.AsyncState;
Socket client = state.Socket;
try
{
//get the read data and see how many bytes we received
int bytesRead = client.EndReceive(result);
//store the data from the buffer
byte[] dataReceived = state.Buffer;
//this will hold the byte data for the number of bytes being received
byte[] totalBytesData = new byte[4];
//load the number byte data from the data received
for (int i = 0; i < 4; i++)
{
totalBytesData[i] = dataReceived[i];
}
//convert the number byte data to a numan readable integer
int totalBytes = BitConverter.ToInt32(totalBytesData, 0);
//create a new array with the length of the total bytes being received
byte[] data = new byte[totalBytes];
//load what is in the buffer into the data[]
for (int i = 0; i < bytesRead - 4; i++)
{
data[i] = state.Buffer[i + 4];
}
//receive packets from the connection until the number of bytes read is no longer less than we need
while (bytesRead < totalBytes + 4)
{
bytesRead += state.Socket.Receive(data, bytesRead - 4, totalBytes + 4 - bytesRead, SocketFlags.None);
}
CommandData commandData;
using (MemoryStream stream = new MemoryStream(data))
{
BinaryFormatter formatter = new BinaryFormatter();
commandData = (CommandData)formatter.Deserialize(stream);
}
ReceivedCommands.Enqueue(commandData);
client.BeginReceive(
state.Buffer,
0,
NetStateObject.BUFFER_SIZE,
SocketFlags.None,
OnReceive,
state
);
dataReceived = null;
totalBytesData = null;
data = null;
}
catch(Exception e)
{
Console.WriteLine("***********************");
Console.WriteLine(e.Source);
Console.WriteLine("***********************");
Console.WriteLine(e.Message);
Console.WriteLine("***********************");
Console.WriteLine(e.InnerException);
Console.WriteLine("***********************");
Console.WriteLine(e.StackTrace);
}
}
答案 0 :(得分:4)
TCP是一种流协议。它没有数据包的概念。可以在多个数据包中发送单个写入调用,并且可以将多个写入调用放入同一个数据包中。因此,您需要在TCP之上实现自己的打包逻辑。
有两种常见的打包方式:
您可以在该数据包的开头存储逻辑数据包的大小。然后你阅读,直到你收到足够的字节来填充数据包并开始反序列化。
答案 1 :(得分:4)
在尝试构建数据并使用它做某事之前,如何确保我的所有数据都已收到?
你必须实现一些协议,所以你知道。
虽然TCP是可靠的,但它不能保证套接字一端的单次写入数据在另一端显示为单次读取:重试,数据包碎片和MTU都可以导致数据被接收到不同的接收器的大小单位。您将按正确的顺序获取数据。
因此,您需要在发送时包含一些信息,以便接收方知道何时有完整的消息。我还建议包括什么样的消息和什么版本的数据(这将构成能够一起支持不同客户端和服务器版本的基础)。
所以发件人发送: - 消息类型 - 消息版本 - 消息大小(以字节为单位)
接收器将循环,使用缓冲区执行读取并将其附加到主缓冲区(MemoryStream
对此有利)。一旦收到完整的标题,它就知道何时收到了完整的数据。
(另一种方法是将一些模式作为“消息结束”标记包含在内,但是你需要处理内容中出现的相同字节序列 - 如果数据是二进制而不是文本则很难做到。)< / p>