c#在同一个Socket上发送多个对象

本文关键字:对象 同一个 Socket | 更新日期: 2023-09-27 17:50:05

我试图从一个套接字发送多个不同的对象(好吧,它们是相同的对象类型,只是具有不同的值)到另一个。我可以用下面的代码发送一个对象:

客户:

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)处阻塞,因为预计会发送另一个对象。

我希望这有意义。指针吗?

c#在同一个Socket上发送多个对象

我强烈推荐大家看看Windows Communication Foundation。它将为您处理所有这些管道,包括通过多个可配置通道对类型进行序列化和反序列化等。

当使用这样的套接字时,我会使用类似protobuf-net的东西而不是BinaryFormatter(警告/披露:我写了它)特别是,如果你每个项目与Serializer.SerializeWithLenthPrefix(...)使用Base128前缀样式(其中一个选项),和一些已知的标签(另一个选项),如1,然后在另一端你可以使用DeserializeItems<Foo>(...)(再次指定Base128和1)。

这将正确地挑选条目,而不会尝试过度读取,直到流关闭,当它将yield break。每个对象都是单独返回的(yield return),所以在给你数据之前,它不会试图消耗整个流。

如果您愿意,它也可以用于异构数据,但同构数据是最简单的。

您可以发送一个头消息,通知接收端期望多少字节。这类似于HTTP中的Content-Length指令。另一种选择是,在末尾发送一个自定义终止字符串(显然,它不能在序列化对象的二进制有效负载中出现,这就是为什么前一种解决方案是我要做的)。

查看TcpListener类:

http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.aspx

或者采纳Reed的建议,看看WCF。

如果你想这么做,这里有一些建议:

  • 发送X字节数并不能保证您将在客户端的一次receive()中接收到它们。您可以在客户端上有一个MemoryStream和一个缓冲区。使用缓冲区接收并写入内存流,直到Receive返回0。
  • 当你发送完数据后,使用client。在调用Close()之前关闭(SocketShutdown.Send)(或。both)。这将阻止客户端的TCP RST。
  • 如果你想序列化多个对象,只需在服务器中一个接一个地序列化它们。然后客户端将缓冲所有传入的数据,当Receive()返回0时,将客户端MemoryStream中的位置移到0,并开始逐个反序列化对象,直到ms.Position == ms.Length。