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

标签 c++ sockets posix wireless openwrt

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

  1. 为什么 sleep 时间必须这么长?
  2. 是否可以通过进一步优化这段代码来减少这个时间?
  3. 如果我不处理接收到的数据包缓冲区,可以吗?或者这会产生问题吗?

请注意,我正在使用 OpenWrt 运行的 radio 上运行此代码.

提前致谢。

代码:

#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;
}

最佳答案

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

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

If space is not available at the sending socket to hold the message to be transmitted and the socket file descriptor does not have O_NONBLOCK set, sendto() shall block until space is available. If space is not available at the sending socket to hold the message to be transmitted and the socket file descriptor does have O_NONBLOCK set, sendto() shall fail.

当您在 sendto 调用之间添加 sleep 时,您可以有效地降低吞吐量并防止套接字缓冲区溢出。

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

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

关于c++ - 无法通过无线网络上的 UDP 广播快速传输,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6337870/

相关文章:

c++ - n 位二进制整数除法

c++ - 为什么我会被核心转储? (Cpp代码)

c# - System.Argument 出现异常 :Specified argument was out of range of valid value

c - Nginx 代理模块和套接字描述符传递

linux - 在 curl 获取的 2 个文件之间添加一个新行

c# - 在 c# .net 中将 posix 样式时区转换为 timezoneinfo

c++ - C/C++ 中的基本多线程——提示、建议、教程、一些方向?

c++ - 为什么 C++ 标准库更喜欢模板而不是枚举?

在多线程应用程序中创建套接字文件描述符(sock fd)

c - 如何根据概率定义rand()?