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与您的多播目标匹配的(s):

~# route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0

因为操作系统网络堆栈根据路由表为多播数据包选择出站接口。这也适用于监听 - 您只需绑定到组地址,内核就会为您选择正确的接口。您仍然必须像往常一样加入该组。

于 2012-09-11T14:32:18.057 回答
2

从手册页:

SO_BINDTODEVICE

将此套接字绑定到特定设备,如“eth0”,如传递的接口名称中指定的那样。如果名称为空字符串或选项长度为零,则移除套接字设备绑定。传递的选项是一个可变长度的以空结尾的接口名称字符串,最大大小为 IFNAMSIZ。如果套接字绑定到接口,则只有从该特定接口接收到的数据包才会被套接字处理。请注意,这只适用于某些套接字类型,尤其是 AF_INET 套接字。数据包套接字不支持它(在那里使用普通的 bind(2) )。

这意味着您必须自己从名称中获取接口,可能使用 getifaddrs,然后绑定到该地址。

于 2012-09-11T14:40:53.843 回答