UDP套接字上的sendto()不连贯行为

时间:2016-12-27 11:36:27

标签: ios c sockets

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

使用通常的fcntl

将套接字设置为非阻塞模式
fcntl(socketfd, F_SETFL, O_NONBLOCK);

为了模拟连接不良,我使用网络链路条件,丢包率为5/5,输出限制为50KBps(在我的情况下保证系统输出缓冲区在某些时候会满了)。

我使用sendto()发送数据,然后通过clock()printf()拨打电话。

以下是我的测试数据,ms中的数据:

  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
  5. 我还注意到,如果20 ms个条目,表示sendto()已立即返回,则说明案例的平均值和标准偏差较小。

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

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

    1. 在阻塞模式下,我希望它阻塞,直到有可用的系统缓冲区来存储数据,而不是数据被丢弃(因为呼叫立即返回)
    2. 在非阻塞模式下,我希望sendto()在阻塞时返回错误,而不是从数据看起来阻塞,直到实际有空间执行它
    3. 行为似乎已被颠倒,但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))
      

1 个答案:

答案 0 :(得分:2)

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

根据UDP page on Wikipedia

  

UDP是一种面向消息的最小传输层协议   记录在RFC 768中。 UDP不保证上层   邮件传递协议,UDP层不保留任何状态   UDP消息一旦发送。因此,有时会引用UDP   as 不可靠的数据报协议。