我正在尝试从一个套接字向另一个套接字发送多个不同的对象(好吧,它们是相同的对象类型,只是具有不同的值)。我可以使用以下代码发送一个对象:
客户端:
var buffer = new byte[1024];
var binFormatter = new BinaryFormatter();
using (var ms = new MemoryStream())
{
int bytesRead;
while ((bytesRead = _clientReceive.Receive(buffer)) > 0);
{
ms.Write(buffer, 0, bytesRead);
}
ms.Position = 0;
message = (Message)binFormatter.Deserialize(ms);
}
服务器:
var gm = new Message { Message = "ObjectType", Object = Data };
using (var mem = new MemoryStream())
{
var binFormatter = new BinaryFormatter();
binFormatter.Serialize(mem, gm);
var gmData = mem.ToArray();
client.Send(gmData, gmData.Length, SocketFlags.None);
client.Close();
}
但如果我想发送多条消息(将完整的客户端代码放在循环中而不是调用client.Close()
),我怎样才能确定客户端何时收到完整的对象?将客户端代码放在这样的循环中:
while (_isReceivingStarted)
{
var buffer = new byte[1024];
var binFormatter = new BinaryFormatter();
using (var ms = new MemoryStream())
{
int bytesRead;
while ((bytesRead = _clientReceive.Receive(buffer)) > 0)
{
ms.Write(buffer, 0, bytesRead);
}
ms.Position = 0;
message = (Message) binFormatter.Deserialize(ms);
}
// Do stuff then wait for new message
}
客户端将挂起_clientReceive.Receive(buffer)
,因为它没有从客户端收到Close()并且永远不会得到0个接收的字节。如果我关闭服务器上的连接,它将循环遍历,然后在Deserialize MemoryStream中出错,而不是在_clientReceive.Receive(buffer)
阻止预期另一个对象被发送。
我希望这是有道理的。有什么指针吗?
答案 0 :(得分:3)
我强烈建议您查看Windows Communication Foundation。它将为您处理所有这些管道,包括通过线路序列化和反序列化您的类型,通过多个可配置的通道等。
答案 1 :(得分:3)
当使用这样的套接字时,我会使用protobuf-net而不是BinaryFormatter
(警告/披露:我写了它)特别是,如果你写每个项目Serializer.SerializeWithLenthPrefix(...)
使用Base128作为前缀样式(其中一个选项),使用一些已知标记(另一个选项),例如1
,然后在另一端使用DeserializeItems<Foo>(...)
(再次指定Base128和1
)。
这将正确地选择项目,而不会尝试过度阅读,直到该流关闭,时间为yield break
。每个对象都会单独返回(yield return
),因此在向您提供数据之前,不会尝试使用整个流。
如果您愿意,它也可以与异构数据一起使用,但同类最简单。
答案 2 :(得分:1)
您可能会发送一条标头消息,通知接收端需要多少字节。这类似于HTTP中的Content-Length指令。其他选项,制作一个你最后发送的自定义终止字符串(显然它不会在序列化对象的二进制有效负载中的任何位置出现,这就是为什么前一个解决方案就是我要做的)。
答案 3 :(得分:0)
查看TcpListener类:
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.aspx
或者按照里德的建议去看看WCF。
答案 4 :(得分:0)
如果你想这样做,这里有一些建议: