开发者

Unable to transmit fast via UDP broadcast on a wireless network

I have the written the following code for transmitting UDP packets via broadcasting on a wireless network. The application 开发者_StackOverflow中文版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;
}


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜