如何指定使用在Linux中一个插座,接口(how to specify which interfac

2019-09-22 07:33发布

是否有可能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权限运行,否则它会抛出一个错误说的“不允许操作。”

Answer 1:

最简单的,也是至今为止最理智的,方法是增加route (S)符合组播目的地:

~# route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0

因为OS网络堆栈选择用于基于所述路由表的多播包的出接口。 这也适用于聆听 - 你只是绑定组地址,内核会选择正确的接口为您服务。 您还必须加入该组像往常一样。



Answer 2:

从手册页:

SO_BINDTODEVICE

结合此接口将像“eth0的”特定装置,如在通过接口名指定。 如果该名称是空字符串或选项长度为零时,插座装置结合被去除。 所传递的选项是一个可变长度空终止接口名称字符串IFNAMSIZ的最大大小。 如果套接字绑定到一个接口,只能从该特定接口接收的分组由插座被处理。 请注意,这仅适用于一些套接字类型,特别是AF_INET插座。 它不支持分组插座(使用普通绑定(2)那里)。

这意味着你必须得到来自自己的名字,可能使用getifaddrs接口,然后绑定到该地址。



文章来源: how to specify which interface to use for a socket in linux