2

udpソケットを特定のインターフェイスにバインドして、そのインターフェイスを介してデータを送信することは可能ですか?複数のUDPソケットを使用してデータを送信するアプリケーションがあり、複数のインターフェイスを備えたマシンで実行されています。次のコードを使用してインターフェイス名を指定することで、これを実行できることを知っています。

int UdpSocket::open(const char *interface)
{
   send_fd_ = ::socket(AF_INET, SOCK_DGRAM, 0);
   if (send_fd_ < 0)
   {
      perror("socket");
      return -1;
   }

   int val = 1;
   int rc = ::setsockopt(send_fd_, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
   if (rc < 0)
   {
      perror("sesockopt");
      close();
      return -1;
   }

   unsigned char ttl = 16;
   rc = ::setsockopt(send_fd_, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
   if (rc < 0)
   {
      perror("sesockopt_ttl");
      close();
      return -1;
   }

   if (interface != NULL)
   {
      struct ifreq ifr;

      memset(&ifr, 0, sizeof(ifr));
      snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), interface);
      rc = ::setsockopt(send_fd_, SOL_SOCKET, SO_BINDTODEVICE, (void*)&ifr, sizeof(ifr));

      if (rc < 0)
      {
         perror("sesockopt");
         close();
         return -1;
      }
   }

   const int flags = ::fcntl(send_fd_, F_GETFL, 0);
   ::fcntl(send_fd_, F_SETFL, flags | O_NONBLOCK);

   return 0;
}

ただし、これにはアプリがroot権限で実行されている必要があります。そうでない場合、「操作は許可されていません」というエラーがスローされます。

4

2 に答える 2

2

最も簡単で、最も健全な方法はroute、マルチキャストの宛先に一致するものを追加することです。

~# route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0

OS ネットワーク スタックは、ルーティング テーブルに基づいてマルチキャスト パケットのアウトバウンド インターフェイスを選択するためです。これはリッスンにも機能します。グループアドレスにバインドするだけで、カーネルが正しいインターフェースを選択します。いつものようにグループに参加する必要があります。

于 2012-09-11T14:32:18.057 に答える
2

マンページから:

SO_BINDTODEVICE

渡されたインターフェース名で指定されているように、このソケットを「eth0」などの特定のデバイスにバインドします。名前が空の文字列であるか、オプションの長さがゼロの場合、ソケット デバイスのバインディングは削除されます。渡されるオプションは、最大サイズが IFNAMSIZ の可変長のヌル終了インターフェイス名文字列です。ソケットがインターフェイスにバインドされている場合、その特定のインターフェイスから受信したパケットのみがソケットによって処理されます。これは一部のソケット タイプ、特に AF_INET ソケットでのみ機能することに注意してください。パケットソケットではサポートされていません (そこでは通常の bind(2) を使用してください)。

これは、おそらく getifaddrs を使用して、自分で名前からインターフェイスを取得し、そのアドレスにバインドする必要があることを意味します。

于 2012-09-11T14:40:53.843 に答える