【问题标题】:c# UDP client server problemsc# UDP客户端服务器问题
【发布时间】:2012-06-25 09:01:36
【问题描述】:

我有一个 udp 客户端和一个 udp 服务器。 udp 客户端和服务器实际上是在物理上断开连接的。 所以我只能向 udp 服务器发送消息,但无法确认数据是否正确接收。

所以我正在做的是发送一个 4 字节的标头,它将指定我将要发送的数据量。 然后根据我之前发送的大小读取数据。

客户端

// Sending Header(header is the size of the data)
byte[] header = BitConverter.GetBytes(data.Count());
socket.SendTo(header, 0, header.Count(), SocketFlags.None, outEP);
// Sending Data
socket.SendTo(data, 0, data.Count(), SocketFlags.None, outEP);

服务器端

// Receiving input size
int receivedCount = socket.EndReceive(result);
// Header is filled on BeginReceive
Int32 count = BitConverter.ToInt32(header, 0);
if(count != receivedCount) throw;
// Then I receive the count relevent
socket.Receive(data, 0, count, SocketFlags.None);

出现了几个问题:

  1. count != receivedCount

    这就是我进行检查的原因,但有时会发生,有时不会。我确实需要最大保证。 我发现当计数不同时,不是因为字节数下降或网络问题。我只是有时没有收到标题 - 只有数据,当我读取 4 个字节时,我实际上读取了 4 个字节的数据,这就是它失败的原因。

    数据只是有时覆盖标题。 这是为什么呢?我该如何解决这个问题?

  2. 有时我也会在 socket.Receive 上收到以下错误

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

    问题是有时会发生,但大多数时候不会... 我可以在最大缓冲区中接收所有内容..但是我会遇到内存问题。

    这应该是高性能和尽可能有保证的交付.. 这必须是 udp,因为服务器端无法物理联系客户端 这是一种方式 - 客户端到服务器。

【问题讨论】:

  • UDP 设计不提供确认对方已收到数据包。如果您想要确认交货,您使用了错误的协议。 UDP 是无状态的。

标签: c# connection udp client-server


【解决方案1】:

UDP 不保证数据包按照您发送它们的顺序到达(或者它们完全到达)。我怀疑任何东西都会被覆盖/覆盖。您必须在一个数据包中发送标头和有效负载。

你考虑过使用 TCP 吗?您可能会争辩说 UDP 更快,但如果您要自己实现数据包重新排序,您将失去这种优势。(错过了它必须是 UDP)。

如果您查看 TCP(网络层处理重传)或SIP over UDP(软件处理重传),则可以检测丢失的数据包并重新传输它们。例如,您可以为您的数据包编号,并让接收者确认收到每个数据包。

【讨论】:

    【解决方案2】:

    在使用 UDP 时,您需要双向通信,并确保没有丢失、重复或混乱的数据包。
    您是否看过像 PGM - Pragmatic Multicast 这样的协议?
    此外,您可能需要一个线程来快速清理网络堆栈,然后将数据发布到队列或其他一些内存数据结构中。网络堆栈比您想象的要小得多,而且比您想象的要快得多。
    编辑: UDP的问题在于,根据定义,你可能丢失或重复包或顺序发生变化,即使接收方检测到它们,当无法通信时,接收方应如何请求更正。

    【讨论】:

    • 我不需要双向通信。我需要一种具有某种交付保证的单向通信。你能进一步解释一下你想用清理网络的单线程说什么吗?
    • 我通常有一个 128 kb 字节数组和一个接收和处理线程。如果 128 kb 已满,那么我知道我太慢了,自己断开连接。
    • 好吧,我的问题是如何缩小数据包丢失的可能性 - 以编程方式 - 也许我可以在每次发送请求后执行 Thread.Sleep() ?也许发送一个数据包然后只有一个大缓冲区?最佳实践是什么?编辑 - 我看到了你的回复。是的,这是一个选择..
    • @Lior - UDP 的设计方式是故意的。如果您不能改用 TCP,则必须自己处理确认。