【问题标题】:sendto() incoherent behaviour on UDP socketUDP 套接字上的 sendto() 不连贯行为
【发布时间】:2016-12-27 11:36:26
【问题描述】:

我在 iOS 上使用 UDP 套接字。将其设置为非阻塞模式和/或模拟不良连接时,我遇到了一种非常奇怪的行为。

使用通常的fcntl 将套接字设置为非阻塞模式:

fcntl(socketfd, F_SETFL, O_NONBLOCK);

为了模拟不良连接,我使用了具有 5/5 输入/输出数据包丢失和 50KBps 输出限制的 Network Link Conditioneer(在我的情况下,这可以保证系统输出缓冲区在某些时候会被填满)。

我使用sendto() 发送数据,并使用clock()printf() 为通话计时。


这是我测试的数据,以毫秒为单位:

  1. 阻塞,连接良好:min 0/max 929/avg 226/std 111
  2. 阻塞,连接错误:min 0/max 611/avg 38/std 84
  3. 非阻塞,良好连接:min 0/max 6244/avg 601/std 1071
  4. 非阻塞,连接错误:min 0/max 5774/avg 400/std 747

我还注意到在2 的情况下,0 ms 的条目很多,这意味着sendto() 已立即返回,这解释了该情况的低平均值和标准偏差。

sendto() 在所有情况下都返回一个正值,对应于请求发送的字节数。

现在,有几件事我无法理解:

  1. 在阻塞模式下,我希望它会阻塞,直到有可用的系统缓冲区来存储数据,似乎数据被丢弃(因为调用立即返回)
  2. 在非阻塞模式下,我希望 sendto() 在阻塞时返回错误,而不是从数据来看,调用似乎会阻塞,直到有实际空间来执行它

这种行为似乎颠倒了,除了 sendto 从不报告失败。

我做错了什么?


套接字创建:

int socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
// error checks
setsockopt(socketfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));

int tos = 0xB8; // VOICE
setsockopt(socketfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));

int rc = fcntl(m_iSocket, F_SETFL, O_NONBLOCK);
if (rc != 0) {
    // error of fcntl is notified
}

发送至:

sendto(socketfd, buffer, buffer_length, 0, (struct sockaddr *) &m_sRemoteHost, sizeof(m_sRemoteHost))

【问题讨论】:

    标签: ios c sockets


    【解决方案1】:

    您如何知道系统的发送缓冲区已满?您只是假设因为您对连接进行了速率限制,所以数据会在发送缓冲区中备份。它更有可能被丢弃在其他地方。由于 UDP 不保证任何数据包都会被传送,因此数据包路径上任何位置的任何软件或硬件都可以随时出于任何原因随意丢弃它。

    根据UDP page on Wikipedia

    UDP 是一个最小的面向消息的传输层协议,它是 记录在 RFC 768 中。UDP 不向上层提供任何保证 用于消息传递的协议,并且 UDP 层不保留 UDP 消息一旦发送。出于这个原因,UDP有时被称为 作为不可靠数据报协议。

    【讨论】:

    • 我了解 UDP 不提供任何保证。我也知道不涉及流量控制。我无法理解的是为什么 sendto() 调用的时间会因连接质量而变化如此之大,我也无法解释为什么它会以这种方式变化。有什么方法可以实际检测到由于传输缓冲区已满而系统实际丢弃了数据包?考虑到没有流量控制,这个缓冲区是否会被填满?
    猜你喜欢
    • 1970-01-01
    • 2015-07-27
    • 2011-02-09
    • 2011-04-25
    • 2020-01-24
    • 2012-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多