【问题标题】:C#: UDP Socket - Receive data with unknown sizeC#: UDP Socket - 接收未知大小的数据
【发布时间】:2010-12-20 22:45:51
【问题描述】:

我使用 UDP 套接字来发送/接收对象。 我将对象序列化为一个字节数组发送它并用客户端接收它。 但在我收到之前,我必须分配一个字节数组。我必须先完成它,然后再处理 S​​ocket.Receive() 方法数组。 但是我的对象长度可变。我怎样才能发现数组大小?

谢谢

编辑:这里是我的接收方法的示例:

BinaryFormatter bf = new BinaryFormatter();

public Object ReceiveUdpPacket()
        {
            byte[] objData = new byte[bufferSize];

            IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 0);
            EndPoint ep = (EndPoint)ipep;
            MemoryStream ms = new MemoryStream();

            udpSocket.ReceiveFrom(objData, ref ep);

            ms.Write(objData, 0, objData.Length);
            ms.Seek(0, SeekOrigin.Begin);

            return (Object)bf.Deserialize(ms);
        }

【问题讨论】:

  • ReceiveFrom 不返回接收到的字节数?

标签: arrays sockets xna udp byte


【解决方案1】:

执行此操作的最典型方法涉及将数据块的前几个字节作为块长度。

因此,例如,如果您的对象大小始终低于 65k 或大约,您可以首先通过套接字将数组大小作为短发送(查看使用 BitConverter 类)。接收者会将它接收到的第一个块读入缓冲区(可能一个与标称 UDP 数据包大小大致相同,大约 512 字节),获取前两个字节,将它们转换为短字节,并为对象设置缓冲区.然后它将继续从套接字读取,直到该缓冲区已满,并将该缓冲区传递给反序列化器。

这当然不包括错误处理等,但这是基本思想。

编辑:

自从我在 .Net 中使用 UDP 做任何事情以来已经有一段时间了,但是这样的事情可能会起作用(在某种程度上是伪代码)

var bigBuffer = new MemoryStream();

//This should be run in a thread
void UdpLoop()
{
   while(!done)
   {
      var buffer = udpClient.Receive();
      bigBuffer.Write(buffer,buffer.Length);
   }
}

void MessageProcessor()
{
   var messageLength = 0;
   while(!done)
   {
      if(bigBuffer.Length > 0 && messageLength == 0)
      {
         var lengthBytes = new byte[2];
         bigBuffer.Read(lengthBytes, 2);
         messageLength = BitConverter.ToInt16(lengthBytes); 
      }
      if(messageLength > 0 && bigBuffer.Length > messageLength)
      {
         var objectBuffer = new byte[messageLength];
         bigBuffer.Read(objectBuffer, messageLength);
         //Do deserialization here
      }
   }
}

这是基本的过程,忽略由于多线程而导致的锁定(从接收块开始,您将不得不处理),以及从内存流中的不同位置读取和写入。希望这足以让您朝着正确的方向前进。

【讨论】:

  • 如何获取前两个字节?我只能一口气从插座中读取。如果缓冲区不够大,我会遇到异常。看起来这个问题对于 udp-sockets 来说是正常的^^
  • 此方法仅适用于面向连接的套接字(例如 TCP),不适用于无连接套接字(例如 UDP)。我不能和 XNA 说话。但是,在 .NET 中,如果消息大于缓冲区,则缓冲区将被消息的第一部分填充,消息的其余部分将丢失,并且将抛出 SocketException。您将不得不一次阅读整个消息,这需要一个足够大的缓冲区来容纳您可能收到的最大消息。
  • 好的,我理解你的方法。但是有一个小问题。看起来您将 .Receive()-Methode 的结果放入流中,但此结果不是对象/字节,结果是 Int(接收到的字节)。这是故意的吗?使用 .Receive-Method 处理的方式是这样的: byte[] objData = new byte[bufferSize]; udpSocket.ReceiveFrom(objData, ref ep);我将把这个例子放在我的问题中。
【解决方案2】:

您可能正在处理大小限制为 64k 或 65535 字节的典型 UDP 数据包。分配一个 64k 字节的数组并将其传递给 Receive() 函数。假设一个典型的套接字实现,Receive() 函数将返回实际接收到的字节数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-20
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-17
    • 1970-01-01
    • 2011-05-08
    相关资源
    最近更新 更多