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

1 に答える 1

2

ソケットを に設定したため、ソケット バッファがオーバーフローしている可能性がありますO_NONBLOCK。通常 (ブロッキングが有効な場合)、ソケット バッファがいっぱいの場合、sendto送信するメッセージを保持するのに十分なバッファ スペースができるまでブロックします。

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

送信するメッセージを保持するためのスペースが送信側ソケットで利用できず、ソケット ファイル記述子に O_NONBLOCK が設定されていない場合、sendto() は、スペースが利用可能になるまでブロックされます。送信するメッセージを保持するためのスペースが送信側ソケットになく、ソケット ファイル記述子に O_NONBLOCK が設定されている場合、sendto() は失敗します。

sleep呼び出しの間に sを追加するsendtoと、スループットが効果的に抑制され、ソケット バッファーのオーバーフローが防止されます。

の代わりにsleep、ブロッキング ソケットを使用する必要があります。ソケット バッファがいっぱいにsendtoなると、ブロックされます。これは、ソケットが次のデータグラムを保持できるようになった瞬間に自動的にスリープを停止することを除いて、実質的にスリープと同じことです。

スループットを向上させるには、MTU サイズに近いデータグラムにデータをまとめてみてください (UDP/IP ヘッダー用に十分なスペースを確保するように注意してください)。これにより、非常に短いデータグラムを送信する場合と比較して、ヘッダーのオーバーヘッドが小さくなります。

于 2011-06-14T03:58:19.277 に答える