我有一个TCP网络程序,它通过连接发送已经序列化并编码到base64的大对象。我写了一个客户端库和一个服务器库,他们都使用NetworkStream's
Begin/EndRead
和Begin/EndWrite
。这是我正在使用的代码(非常简化的版本):
对于服务器:
var Server = new TcpServer(/* network stuffs */);
Server.Connect();
Server.OnClientConnect += new ClientConnectEventHandler(Server_OnClientConnect);
void Server_OnClientConnect()
{
LargeObject obj = CalculateLotsOfBoringStuff();
Server.Write(obj.SerializeAndEncodeBase64());
}
然后是客户:
var Client = new TcpClient(/* more network stuffs */);
Client.Connect();
Client.OnMessageFromServer += new MessageEventHandler(Client_OnMessageFromServer);
void Client_OnMessageFromServer(MessageEventArgs mea)
{
DoSomethingWithLargeObject(mea.Data.DecodeBase64AndDeserialize());
}
客户端库具有NetworkStream.BeginRead
的回调方法,该方法触发事件OnMessageFromServer
,该事件将数据作为字符串通过MessageEventArgs
传递。
但是,当通过BeginRead/EndRead
接收大量数据时,它似乎在多条消息上分散。例如。假装这是一个很长的信息:
"This is a really long message except not because it's for explanatory purposes."
如果这确实是一个很长的消息,Client_OnMessageFromServer
可能会被调用...说三次“长消息”的碎片部分:
"This is a really long messa"
"ge except not because it's for explanatory purpos"
"es."
Soooooooo .... 深呼吸
在Begin/EndWrite
的一次通话中,通过一个Client_OnMessageFromServer
发送所有内容的最佳方法是什么?
答案 0 :(得分:5)
你做不到。在TCP上,事物的到达方式不一定与发送方式相同。 您的代码的工作是知道什么构成完整的消息,并在必要时缓冲传入的数据,直到您 完整的消息为止小心不要丢弃下一个消息的开始我在这个过程中。
在文本协议中,这通常意味着“发现换行符/ nul-char”。对于二进制,它通常意味着“在消息的前导码中读取长度标题”。
答案 1 :(得分:4)
TCP是一种流协议,没有固定的消息边界。这意味着您可以接收部分信息或一部分的结尾和另一部分的开头。
有两种方法可以解决这个问题: