Невозможно быстро передать через UDP-трансляцию в беспроводной сети - PullRequest
0 голосов
/ 14 июня 2011

Я написал следующий код для передачи пакетов UDP через широковещательную рассылку по беспроводной сети.Приложение, которое я пытаюсь разработать, требует очень быстрой передачи пакетов, но, к сожалению, я не могу этого сделать и мне нужно добавить время ожидания.Я обнаружил, что при времени ожидания менее 500 мс я не могу успешно отправить все пакеты.

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

1 Ответ

2 голосов
/ 14 июня 2011

Возможно, вы переполняете буфер сокетов, потому что вы установили сокет на O_NONBLOCK.Обычно (когда блокировка включена), если буфер сокета заполнен, sendto блокируется, пока не будет достаточно места в буфере для хранения сообщения для отправки.

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

Если на передающем сокете нет места для хранения сообщения, подлежащего передаче, и в дескрипторе файла сокета не установлено значение O_NONBLOCK, sendto () блокируется до тех пор, пока не освободится место.Если на передающем сокете нет места для хранения сообщения, подлежащего передаче, и в дескрипторе файла сокета установлен O_NONBLOCK, sendto () завершится ошибкой.sendto вызывает, вы эффективно снижали пропускную способность и не допускали переполнения буферов сокетов.

Вместо sleep вы должны использовать блокирующий сокет.Если буферы сокета заполнятся, sendto заблокирует, что фактически аналогично сну, за исключением того, что он автоматически прекратит спать, как только сокет сможет удержать вашу следующую дейтаграмму.Несмотря на это, попробуйте объединить данные в дейтаграммы, близкие к размеру MTU (стараясь сохранить достаточно места для заголовков UDP / IP).Это должно снизить затраты заголовка по сравнению с отправкой очень коротких дейтаграмм.

...