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

发布于 2024-11-15 01:28:33 字数 3205 浏览 6 评论 0原文

我编写了以下代码,用于通过无线网络上的广播传输 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: %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;
}

I have the written the following code for transmitting UDP packets via broadcasting on a wireless network. The application that I have trying to develop requires the packets to be transmitted very fast, but unfortunately I cannot do so and need to add a sleep time. I find that below 500us sleep time, I am unable to send all the packets successfully.

  1. Why does the sleep time have to be so high?
  2. Is it possible to reduce this time by further optimization of this code?
  3. If I do not process the received packets buffer, is it okay? Or does this create problems?

Note that I am running this code on a wireless radio which runs using OpenWrt.

Thanks in advance.

Code:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

镜花水月 2024-11-22 01:28:33

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

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

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

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

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

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

You are probably overflowing the socket buffer because you set the socket to O_NONBLOCK. Normally (when blocking is enabled), if the socket buffer is full, sendto blocks until there is sufficient buffer space to hold the message for sending.

From 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.

When you added sleeps between your sendto calls, you were effectively throttling down the throughput and preventing the socket buffers from overflowing.

Instead of sleep, you should use a blocking socket. If the socket buffers become full, sendto will block, which is effectively the same thing as sleeping, except that it will automatically stop sleeping the instant the socket is able to hold your next datagram.

To achieve better thoughput, try lumping data into datagrams close to the MTU size (while taking care to save enough room for UDP/IP headers). This should give you smaller header overhead compared to sending very short datagrams.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文