无法通过无线网络上的UDP广播快速传输

时间:2011-06-14 00:22:28

标签: c++ sockets posix wireless openwrt

我已经编写了以下代码,用于通过无线网络上的广播传输UDP数据包。我试图开发的应用程序要求数据包传输速度非常快,但不幸的是我不能这样做,需要增加一个睡眠时间。我发现在500us以下的睡眠时间内,我无法成功发送所有数据包。

  1. 为什么睡眠时间必须这么高?
  2. 是否可以通过进一步优化此代码来缩短这段时间?
  3. 如果我不处理收到的数据包缓冲区,可以吗?或者这会产生问题吗?
  4. 请注意,我在使用OpenWrt运行的无线电台上运行此代码。

    提前致谢。

    代码:

    #include <sys/types.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <string.h>
    #include <netdb.h>
    #include <stdio.h>
    
    #include <fcntl.h>
    #include <string.h>
    #include <sys/time.h>
    #include <arpa/inet.h>  /* for sockaddr_in */
    
    #define BROADCAST_IP "192.168.255.255"
    #define BROADCAST_PORT 45454
    
    int b_sock=-1;
    
    void init_socket()
    {
      unsigned short b_port = BROADCAST_PORT;
      struct sockaddr_in b_addr;
      int broadcastPermission;
      char* rx_ip = BROADCAST_IP;
    
      if ((b_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
        perror("socket() failed");
    
      /* Set socket to allow broadcast */
      broadcastPermission = 1;
      if (setsockopt(b_sock, SOL_SOCKET, SO_BROADCAST, (void *) &broadcastPermission, sizeof(broadcastPermission)) < 0)
        perror("setsockopt() failed");
    
      int opts;
      opts = fcntl(b_sock,F_GETFL);
      if(opts < 0)
        perror("fcntl get failed");
    
      opts = (opts | O_NONBLOCK);
      if(fcntl(b_sock,F_SETFL,opts) < 0)
        perror("fcntl set failed");
    
      memset(&b_addr, 0, sizeof(b_addr));   /* Zero out structure */
      b_addr.sin_family = AF_INET;                 /* Internet address family */
      b_addr.sin_addr.s_addr = inet_addr(rx_ip);/* Broadcast IP address */
      b_addr.sin_port = htons(b_port);         /* Broadcast port */
    
      if (bind(b_sock, (struct sockaddr *) &b_addr, sizeof(b_addr)) < 0)
        perror("rx bind() failed");
    }
    
    void send_thread_body(long int buf, struct sockaddr_in tx_addr)
    {
      if(sendto(b_sock, &buf, sizeof(long int), 0, (struct sockaddr *)&tx_addr, sizeof(tx_addr)) < 0)
        printf("tx sent diff num bytes than expected: %d\n",buf);
    }
    
    
    int main(int argc, char *argv[])
    {
      init_socket();
      {
        timeval start, end;
        double diff = 0;
        long int num = 0;
    
        char *tx_ip = BROADCAST_IP;
        unsigned short tx_port = BROADCAST_PORT;
        struct sockaddr_in tx_addr;
    
        memset(&tx_addr, 0, sizeof(tx_addr));   /* Zero out structure */
        tx_addr.sin_family = AF_INET;                 /* Internet address family */
        tx_addr.sin_addr.s_addr = inet_addr(tx_ip);/* Broadcast IP address */
        tx_addr.sin_port = htons(tx_port);         /* Broadcast port */
    
        double next = 0;
        double st = 0;
    
        while (num<50000)
        {
          while (st <= next)
          {
            gettimeofday(&start,NULL);
            st = start.tv_sec*1000 + ((double)start.tv_usec)/1000.0;
          }
    
          send_thread_body(num,tx_addr);
    
          gettimeofday(&end, NULL);
          diff += ((double)(((end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec))))/1000000.0;
    
          num++;
    
          next = end.tv_sec*1000 + ((double)end.tv_usec)/1000.0 + 0.7;
        }
    
        printf("Avg time diff: %f\n",diff/50000.0);
      }
      close(b_sock);
      return 0;
    }
    

1 个答案:

答案 0 :(得分:2)

您可能会溢出套接字缓冲区,因为您将套接字设置为O_NONBLOCK。通常(当启用阻塞时),如果套接字缓冲区已满,sendto将阻塞,直到有足够的缓冲区空间来保存要发送的消息。

来自http://pubs.opengroup.org/onlinepubs/009695399/functions/sendto.html

  

如果没有空间   发送套接字以保存消息   被传输和套接字文件   描述符没有O_NONBLOCK   set,sendto()应阻塞直到空格   是可用的。如果没有空间   在发送套接字可用   保持要传输的信息和   套接字文件描述符确实有   O_NONBLOCK set,sendto()将失败。

当您在sleep次调用之间添加sendto时,您实际上是在限制吞吐量并阻止套接字缓冲区溢出。

而不是sleep,您应该使用阻塞套接字。如果套接字缓冲区已满,sendto将被阻塞,这实际上与休眠相同,只是它会在套接字能够保存下一个数据报的瞬间自动停止休眠。

要获得更好的吞吐量,请尝试将数据集中到接近MTU大小的数据报(同时注意为UDP / IP标头保留足够的空间)。与发送非常短的数据报相比,这应该会带来更小的头部开销。