【问题标题】:size of the next queued datagram - UDP下一个排队数据报的大小 - UDP
【发布时间】:2012-01-17 12:58:39
【问题描述】:

我正在使用 System.Net.Sockets Socket 类来接收 UDP 数据报。 我想知道收到的数据报的确切长度,以便检查数据报的有效性。

Socket.Receive(Byte()) 方法文档说:

如果您使用的是无连接 Socket,Receive 将从您在 Connect 方法中指定的目标地址读取第一个排队的数据报。如果您收到的数据报大于缓冲区参数的大小,则缓冲区会被消息的第一部分填充,多余的数据将丢失并抛出 SocketException。

Socket.Available 属性给出了可供读取的总字节数,这是所有排队数据报大小的总和。

有没有办法可以找出下一个数据报的大小?

public static void Receive()
{
    Byte[] buf, discardbuf;
    const int paklen = 32;                  //correct packet length
    int l;

    buf = new Byte[paklen];
    discardbuf = new Byte[4096];

    while (rcv_enable)
    {
        l = soc.Available;
        if (l == 0) continue;
        if (l == paklen) soc.Receive(buf);  //receive the correct packet
        else soc.Receive(discardbuf);       //discard otherwise
        Thread.Sleep(200);
        Console.WriteLine("Received {0}", l);
    };
}

【问题讨论】:

    标签: c# .net sockets udp datagram


    【解决方案1】:

    我将假设您已经开发了自己的协议,并且期望数据报具有预先知道的大小,并且您希望保护自己免受恶意数据包的侵害。

    由于性能似乎是一个问题,并且您想避免异常,我会查看overload of Receive,它返回原始套接字错误而不是抛出异常。 MSDN 文档确实(错误地?)声明此方法也会引发异常,但我认为情况并非如此。绝对值得一试。

    SocketError error;
    byte[] buffer = new byte[512]; // Custom protocol max/fixed message size
    int c = this.Receive(buffer, 0, buffer.Length, SocketFlags.None, out error);
    
    if (error != SocketError.Success)
    {
        if(error == SocketError.MessageSize)
        {
            // The message was to large to fit in our buffer
        }
    }
    

    使用一个预先知道的合理大小的缓冲区,并使用重载检查 SocketError 错误代码,以确定读取是否成功或是否应该丢弃包。

    但是,如果您自己的协议可以发送未知大小的数据报,直到最大数据报大小的限制,您别无选择,只能分配足够大的缓冲区以容纳最大的数据包 (65k)(您可以使用缓冲池来根据您的代码避免内存问题)。

    还可以查看SocketFlags enum,它包含一些您可能感兴趣的成员,例如 Partial 和 Peek 成员。

    【讨论】:

    • 完美!这个重载完成了这项工作,并且没有抛出异常。看来,MSDN 文档不正确。谢谢。 -顺便说一句,我在 MSDN 中找不到 SocketFlags enum 的任何相关示例。
    • @Anniffer 太好了,如果它解决了您的问题,请随时接受这个答案:)
    【解决方案2】:

    为什么不直接检查Receive 的返回值呢?我很确定每次调用都会返回一个数据报。

    【讨论】:

    • 它会工作,但我总是需要将数据读入更大的缓冲区。否则,如果缓冲区小于数据报大小,Receive() 将抛出异常 错误代码:10040 在数据报套接字上发送的消息大于内部消息缓冲区或其他网络限制,或者用于接收数据报的缓冲区小于数据报本身 --实际上这是一个高性能代码,异常太昂贵而无法抛出和处理
    • 啊,好吧,不幸的是,我不是 .NET 专家,但一种解决方案可能是找出您要接收数据报的所有接口的最大 MTU。另一种解决方案是将缓冲区硬编码为 65535 字节,因为这是最大 UDP 数据报大小(16 位长度字段),实际实际最大值要小一些,65535 - IP-header - UDP-header。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-12
    • 1970-01-01
    • 2019-12-17
    • 1970-01-01
    • 2021-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多