无法在无线网络上通过UDP广播进行快速传输

Unable to transmit fast via UDP broadcast on a wireless network

本文关键字:广播 传输 UDP 无线网络      更新时间:2023-10-16

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

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

请注意,我正在使用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: %dn",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: %fn",diff/50000.0);
  }
  close(b_sock);
  return 0;
}

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

发件人http://pubs.opengroup.org/onlinepubs/009695399/functions/sendto.html:

如果在发送套接字以将消息保存到和套接字文件描述符没有O_NONBLOCKset,sendto()将阻塞直到空格可用。如果空间不是在发送套接字上可用保存要发送的消息,以及套接字文件描述符具有O_NONBLOCK设置,sendto()将失败。

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

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

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