【问题标题】:UDP non blocking write failureUDP非阻塞写失败
【发布时间】:2013-12-10 08:32:14
【问题描述】:

我曾在非阻塞 TCP 中工作,因为在非阻塞情况下读取和写入都可能失败。如果没有可用数据,TCP 非阻塞读取可能会失败,如果对端的 TCP 缓冲区已满(我希望 TCP 缓冲区大小为 64K),则 TCP 写入可能会失败。

类似地,如果没有可用数据,UDP 读取 (recvfrom) 可能会失败。但是 UDP 写入的失败案例是什么(sendto)。我认为在 UDP 写入中不会有任何非块错误。因为 TCP write 发送数据并等待来自另一端的 ACK。但是对于 UDP 写入,情况并非如此,它只会发送并出来,并且不会等待来自对等方的任何 ACK。如果它不发送到另一端意味着它的数据包丢失。

我对UDP非阻塞写的理解是否正确?请解释一下?

【问题讨论】:

  • 可能有很多原因。当你写失败时,你检查 errno 的值是多少?

标签: c sockets network-programming udp nonblocking


【解决方案1】:

UDP 非阻塞发送失败的最可能原因是 UDP 套接字的内核内传出数据缓冲区已满。在这种情况下,send()/sendto() 将返回 -1 并且 errno 将设置为 EWOULDBLOCK。

请注意,非阻塞的 send()/sendto() 在返回之前实际上不会将数据发送到网络设备;相反,它将数据复制到内核缓冲区并立即返回,然后内核负责尽快将数据移出网络。如果您的程序尝试一次发送大量数据,则传出数据缓冲区可能会变满,因为 CPU 将新数据添加到缓冲区的速度比网络硬件将缓冲区的数据转发到网络的速度要快得多。

如果您收到 -1/EWOULDBLOCK 错误,通常最优雅的处理方法是停止尝试在该套接字上发送,直到套接字 select()(或 poll() 等)为准备写。发生这种情况时,您知道内核缓冲区至少已部分耗尽,您可以再次尝试 send()/sendto() 调用。

另一个(不太可能)导致 send() 错误的原因是您尝试发送到的 IP 地址无效。在任何情况下,您都应该检查 errno 并找出 errno 的值是什么,因为这可以让您更好地了解问题所在。

顺便说一句,上述行为也不是 UDP 独有的;如果您尝试在套接字上发送()数据的速度快于本地网卡可以耗尽套接字的输入,那么您可以并且将会遇到与非阻塞 TCP 套接字相同的问题(即使远程对等方的接收窗口未满)内核缓冲区。

【讨论】:

    【解决方案2】:

    因为TCP write发送数据并等待对方的ACK。

    不,它没有。它将您的数据复制到套接字发送缓冲区中,如果已满,它将阻塞或返回-1/EWOULDBLOCK/EAGAIN.

    但是对于 UDP 写入情况并非如此,它只会发送并出来,它不会等待来自对等方的任何 ACK。

    不,它没有。它将您的数据复制到套接字发送缓冲区中,如果已满,它将阻塞或返回-1/EWOULDBLOCK/EAGAIN.

    在这两种情况下,实际将字节放到线路上与您的程序是异步的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-18
      • 1970-01-01
      • 1970-01-01
      • 2011-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多