绑定多播(UDP)套接字是什么意思?


71

我在具有多个网络接口的主机之间使用多播UDP。我正在使用boost :: asio,并且被接收者必须进行的2个操作所迷惑:绑定,然后加入组。

当您对加入的每个多播组进行设置时,为什么在绑定期间需要指定接口的本地地址?

姊妹问题涉及多播端口:由于在发送期间,您发送到多播地址和端口,为什么在订阅多播组期间仅指定地址,而不指定端口-在对的混乱调用中指定的端口绑定。

注意:“ join-group”是over的包装setsockopt(IP_ADD_MEMBERSHIP),如所记录的那样,可以在同一套接字上多次调用该包装以订阅不同的组(通过不同的网络?)。因此,每次我订阅一个组时,放弃绑定调用并指定端口是很有意义的。

从我看来,始终绑定到“ 0.0.0.0”并在加入组时指定接口地址,效果很好。困惑。

Answers:


61

在接收多播时绑定UDP套接字意味着指定从中接收数据的地址和端口(不是本地接口,TCP接受器绑定就是这种情况)。在这种情况下,指定的地址具有过滤作用,即,套接字将仅接收发送到该多播地址和端口的数据报,而不管套接字随后加入了什么组。这解释了为什么绑定到INADDR_ANY(0.0.0.0)时,我会收到发送到多播组的数据报,而绑定到任何本地接口时,我却什么都没收到,即使数据报是在该接口所连接的网络上发送的也是如此对应。

引自UNIX®Network Programming Volume 1,第三版:WR Stevens编写的Sockets Networking API。21.10。发送和接收

[...]我们希望接收套接字绑定多播组和端口,例如239.255.1.2端口8888。(回想一下,我们可以只绑定通配符IP地址和端口8888,但是绑定多播地址会阻止套接字接收可能到达端口8888的任何其他数据报。)然后,我们希望接收套接字加入多播组。发送套接字将数据报发送到该相同的多播地址和端口,例如239.255.1.2端口8888。


做这个实验:在同一个应用程序中-创建2个套接字,将每个套接字加入不同的组。将流量发送到两个组(使用相同的端口号!)-如果在绑定时未设置地址,则两个组都将获得流量,我想...
13年

1
@nhed:在Linux上,它甚至不必处于同一进程中。绑定到0.0.0.0时,您将收到到该端口的所有多播流量,您和主机上的其他进程为此端口添加了组成员身份。
Johannes Overmann

@JohannesOvermann,同意。我只是提出一个简单的测试来表明OP断言always binding to "0.0.0.0" and specifying the interface address when joining the group, works very well是错误的
Nhed

为什么错了?注意:我所说的“做得很好”不是很明确。我的意思是,绑定到“ 0.0.0.0”可以帮助我接收流量,而不是绑定到发送流量的网络的本地接口IP,这无济于事。被接受的答案解释了为什么会这样。
haelix

52

“绑定”操作的基本意思是,“使用此本地UDP端口发送和接收数据。换句话说,它将分配该UDP端口供您的应用程序专用。(TCP套接字也是如此)。

当您绑定到“ 0.0.0.0”时(INADDR_ANY)时,基本上是在告诉TCP / IP层使用所有可用的适配器进行侦听,并选择最佳的适配器进行发送。这是大多数套接字代码的标准做法。仅当您要在特定的网络适配器上发送/接收时,才不会为IP地址指定0。

同样,如果在绑定期间将端口值指定为0,则操作系统将为该套接字分配一个随机可用的端口号。因此,对于UDP多播,我希望您在希望将多播流量发送到的特定端口号上绑定到INADDR_ANY。

需要执行“加入多播组”操作IP_ADD_MEMBERSHIP,因为它基本上告诉您的网络适配器不仅侦听目标MAC地址是您自己的以太网帧,而且还告诉以太网适配器(NIC)侦听IP组播流量,如下所示:对应的组播以太网地址。每个多播IP都映射到一个多播以太网地址。当您使用套接字发送到特定的多播IP时,以太网帧上的目标MAC地址将设置为该多播IP对应的多播MAC地址。加入多播组时,您正在配置NIC以侦听发送到相同MAC地址(除了其自己的MAC地址)的流量。

没有硬件支持,多播将不会比普通广播IP消息更有效。加入操作还告诉您的路由器/网关转发来自其他网络的多播流量。(有人记得MBONE吗?)

如果加入多播组,则NIC将接收该IP地址上所有端口的所有多播通信。只有发往您绑定的监听端口的流量才会通过TCP / IP堆栈传递到您的应用程序。关于为什么在多播订阅期间指定端口的原因-这是因为多播IP就是那个-仅IP。“端口”是上层协议(UDP和TCP)的属性。

您可以阅读有关在各个站点上组播IP地址如何映射到组播以太网地址的更多信息。 Wikipedia文章的内容是:

IANA拥有OUI MAC地址01:00:5e,因此,使用以太网MAC地址范围01:00:5e:00:00:00-01:00:5e:7f:ff:ff传送多播数据包。这是23位的可用地址空间。第一个八位位组(01)包括广播/多播位。28位多播IP地址的低23位映射到可用以太网地址空间的23位。


1
感谢您的关注,谢尔比。因此,bind(0.0.0.0)的使用是相关的,因为它指定了接收传入单播UDP数据包的接口?绑定时,我尝试使用0.0.0.0以外的设置,但没有任何效果(甚至没有发送多播流量所经过的网络的特定接口)。我仍然不理解bind()地址的含义。
haelix

小提示,对于TCP,它的作用非常明显bind(interfAddr, port)。它只接受来自该特定网络的连接,我已验证这是正确的。但是对于UDP套接字,绑定地址对于IP_ADD_MEMBERSHIP的第二个参数似乎是多余的。由于设置似乎无效,因此并非完全多余-仅0.0.0.0有效。
haelix 2012年

不知道您所说的“什么都不起作用”。发布一些演示问题的代码。至于冗余问题-我想您可以绑定到所有适配器(INADDR_ANY == 0.0.0.0),然后在特定接口上进行多播注册。我怀疑他们只是想让界面灵活。请阅读此链接的6.4节-tldp.org/HOWTO/Multicast-HOWTO-6.html,以了解有关为何需要传递接口的类似讨论。
2012年

“无用”是指绑定UDP套接字时,除INADDR_ANY(0.0.0.0)以外的其他地址均不适用(甚至组播流量通过的接口地址也无法到达该机器,即加入时指定为第二个参数的那个地址)群组)。绑定期间没有错误,只是read()没有任何结果(永远挂起)。
haelix 2012年

1
这似乎不适用于多播接收器。这里的IP不是接口。它可以是ANY或多播组地址。
WiSaGaN

10

绑定多播(udp)套接字是什么意思的更正只要在以下引用中部分正确:

“绑定”操作的基本意思是,“使用此本地UDP端口发送和接收数据。换句话说,它将分配该UDP端口供您的应用程序专用

有一个例外。如果应用了该选项,则多个应用程序可以共享同一端口进行侦听(通常对于多播数据报具有实用价值)SO_REUSEADDR。例如

int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); // create UDP socket somehow
...
int set_option_on = 1;
// it is important to do "reuse address" before bind, not after
int res = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &set_option_on, 
    sizeof(set_option_on));
res = bind(sock, src_addr, len);

如果多个进程进行了这种“重用绑定”,则在该共享端口上接收到的每个UDP数据报都将传递到每个进程(提供与多播流量的自然联合)。

以下是有关在某些情况下发生的情况的更多详细信息:

  1. 尝试将任何绑定(“独占”或“重用”)绑定到空闲端口将成功

  2. 如果端口已经“重用绑定”,则尝试“独占绑定”将失败

  3. 如果某些进程保留“独占绑定”,则尝试“重用绑定”将失败


7

区分SENDING多播套接字和RECEIVING多播套接字也非常重要。

我同意以上关于接收多播套接字的所有答案。OP指出将RECEIVING套接字绑定到接口没有帮助。但是,必须将多播SENDING套接字绑定到接口。

对于多宿主服务器上的SENDING多播套接字,为要发送到的每个接口创建一个单独的套接字非常重要。应该为每个接口创建一个绑定的SENDING套接字。

  // This is a fix for that bug that causes Servers to pop offline/online.
  // Servers will intermittently pop offline/online for 10 seconds or so.
  // The bug only happens if the machine had a DHCP gateway, and the gateway is no longer accessible.
  // After several minutes, the route to the DHCP gateway may timeout, at which
  // point the pingponging stops.
  // You need 3 machines, Client machine, server A, and server B
  // Client has both ethernets connected, and both ethernets receiving CITP pings (machine A pinging to en0, machine B pinging to en1)
  // Now turn off the ping from machine B (en1), but leave the network connected.
  // You will notice that the machine transmitting on the interface with
  // the DHCP gateway will fail sendto() with errno 'No route to host'
  if ( theErr == 0 )
  {
     // inspired by 'ping -b' option in man page:      
     //      -b boundif
     //             Bind the socket to interface boundif for sending.
     struct sockaddr_in bindInterfaceAddr;
     bzero(&bindInterfaceAddr, sizeof(bindInterfaceAddr));
     bindInterfaceAddr.sin_len = sizeof(bindInterfaceAddr);
     bindInterfaceAddr.sin_family = AF_INET;
     bindInterfaceAddr.sin_addr.s_addr = htonl(interfaceipaddr);
     bindInterfaceAddr.sin_port = 0; // Allow the kernel to choose a random port number by passing in 0 for the port.
     theErr = bind(mSendSocketID, (struct sockaddr *)&bindInterfaceAddr, sizeof(bindInterfaceAddr));
     struct sockaddr_in serverAddress;
     int namelen = sizeof(serverAddress);  
     if (getsockname(mSendSocketID, (struct sockaddr *)&serverAddress, (socklen_t *)&namelen) < 0) {
        DLogErr(@"ERROR Publishing service... getsockname err");
     }
     else
     {
        DLog( @"socket %d bind, %@ port %d", mSendSocketID, [NSString stringFromIPAddress:htonl(serverAddress.sin_addr.s_addr)], htons(serverAddress.sin_port) );
     }

如果没有此修复程序,则多播发送将间歇性地获取sendto()errno'到主机没有路由'。如果有人能阐明为什么拔出DHCP网关会导致Mac OS X多播SENDING套接字感到困惑,我很想听听。


1
Wonderfull的答案,解决我有关多播的问题。
lygstate
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.