1

我目前正在用 C# 编写一些异步 UDP 网络代码。我正在来回发送小数据包(到目前为止每个数据包不到 50 个字节),我的第一个想法是将它们分成两个不同的数据包,仍然作为一个数据包发送,但作为两个数据包接收。因此,一个报头或一个额外的信息包总是被添加到实际包的开头。这将包含一个 ID 和数据长度。

所以我想我可以在接收端(异步接收)拆分它,首先接收标头,然后接收实际信息。这样我就不必担心数据包和“数据包头”之间的顺序。

所以我写的代码基本上是这样工作的:客户端向服务器发送 30 个字节的数据,其中前 3 个字节是数据包头。

服务器会调用 (PACKET_HEADER_SIZE = 3):

socket.BeginReceiveFrom(state.Buffer, 0, PACKET_HEADER_SIZE, SocketFlags.None, ref endPoint, ReceivePacketInfo, state);

然后接收数据:

private void ReceivePacketInfo(IAsyncResult ar)
{
    StateObj state = (StateObj) ar.AsyncState;
    int bytesRead = socket.EndReceiveFrom(ar, ref endPoint);
    state.BytesReceived += read;
    if (state.BytesReceived < state.Buffer.Length)
    {
        _socket.BeginReceiveFrom(state.Buffer, state.BytesReceived, state.Buffer.Length - state.BytesReceived, SocketFlags.None, ref endPoint, ReceivePacketInfo, state);
    }
    else
    {
        //my thought was to receive the rest of the packet here
    }
}

但是当调用 socket.EndReceiveFrom(ar) 我得到一个 SocketException:

“在数据报套接字上发送的消息大于内部消息缓冲区或其他网络限制,或者用于接收数据报的缓冲区小于数据报本身”

所以现在我有几个问题。

在调用 EndReceiveFrom 之前,我是否必须确保我收到了整个数据包(在这种情况下是标头和数据包)?

我可以假设我要么一次性得到整个数据包,要么什么也得不到,这样我在 ReceivePacketInfo 中的 if 语句将是多余的(当然,只要它的大小小于最大数据包大小)?

如果我不能,有没有解决我问题的好方法?我想我可以标记我所有的数据包头和我的所有数据包以便能够将它们映射在一起。我也可以尝试有一个标准化的“数据包结尾”,这样我就可以一直阅读,直到我到达数据包的末尾。

提前感谢您的帮助!

4

1 回答 1

2

我可以假设我要么一口气拿到整个数据包,要么一无所获

这几乎是 UDP 唯一可以保证的——数据包的内容。如果收到数据包,则保证它具有相同的大小和相同的内容。所以你必须确保你的缓冲区足够大以容纳一个数据包。

不保证数据包的顺序和交付本身。由您和您的应用程序来处理丢弃的数据包和乱序的数据包。

于 2013-05-20T19:43:24.983 回答