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

hae*_*lix 65 sockets udp bind multicast boost-asio

我在具有多个网络接口的主机之间使用多播UDP.我正在使用boost :: asio,并且被接收器必须进行的2个操作混淆:bind,然后是join-group.

当您对加入的每个组播组执行此操作时,为什么需要在绑定期间指定接口的本地地址?

姐妹问题是关于多播端口:因为在发送期间,您发送到多播地址和端口,为什么在订阅多播组期间,您只需指定地址,而不是端口 - 在混乱的呼叫中指定的端口绑定.

注意:"join-group"是一个包装器setsockopt(IP_ADD_MEMBERSHIP),如文档所示,可以在同一个套接字上多次调用以订阅不同的组(通过不同的网络?).因此,每次订阅组时,抛弃绑定调用并指定端口是完全合理的.

从我所看到的,总是绑定到"0.0.0.0"并在加入组时指定接口地址,效果非常好.困惑.

hae*_*lix 56

在接收多播时绑定UDP套接字意味着指定从中接收数据的地址和端口(不是本地接口,如TCP接受器绑定的情况).在这种情况下指定的地址具有过滤角色,即套接字将仅接收发送到该多播地址和端口的数据报,无论随后哪个组由套接字连接.这解释了为什么当绑定到INADDR_ANY(0.0.0.0)时,我收到发送到我的多播组的数据报,而当绑定到任何本地接口时,我没有收到任何内容,即使数据报是在该接口所在的网络上发送的对应.

引用UNIX®NetworkProgramming第1卷,第3版:WR Stevens的套接字网络API.21.10.发送和接收

[...]我们希望接收套接字绑定的多播组和端口,说239.255.1.2的端口8888(回想一下,我们可以只绑定通配符IP地址和端口号8888,但结合多播地址防止插座从接收可能到达目的地为端口8888的任何其他数据报.)然后,我们希望接收套接字加入多播组.发送套接字将数据报发送到同一个多播地址和端口,比如239.255.1.2端口8888.


sel*_*bie 49

"绑定"操作基本上是说"使用此本地UDP端口发送和接收数据.换句话说,它将该UDP端口分配给您的应用程序专用.(对于TCP套接字也是如此).

当您绑定到"0.0.0.0"( INADDR_ANY),你基本上说的是TCP/IP层使用所有可用适配器的听力和选择最佳适配器发送.这是大多数套接字代码的标准做法.您不希望在IP地址上指定0的唯一情况是您希望在特定网络适配器上发送/接收.

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

"加入组播组"操作(IP_ADD_MEMBERSHIP需要),因为它主要是告诉您的网络适配器听不仅为以太网数据帧在目的MAC地址是你自己的,它也告诉了以太网适配器(NIC)来监听IP组播流量为以及相应的多播以太网地址.每个多播IP映射到多播以太网地址.使用套接字发送到特定的组播IP时,以太网帧上的目标MAC地址将设置为组播IP的相应组播MAC地址.当您加入多播组时,您正在配置NIC以侦听发送到同一MAC地址的流量(除了它自己的).

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

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

您可以阅读有关多播IP地址如何映射到各个站点的多播以太网地址的更多信息. 维基百科的文章和它一样好:

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位可用以太网地址空间.

  • 这似乎不适合多播接收器。这里的IP不是接口。它可以是 ANY,也可以是多播组地址。 (2认同)

Yur*_*ula 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);
Run Code Online (Sandbox Code Playgroud)

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

以下是有关在少数情况下会发生什么的更多细节:

  1. 尝试任何绑定("独占"或"重用")到自由端口将成功

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

  3. 如果某些进程保持"独占绑定",尝试"重用绑定"将失败


Kei*_*ber 5

将SENDING多播套接字与RECEIVING多播套接字区分开来也非常重要.

我同意上面关于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) );
     }
Run Code Online (Sandbox Code Playgroud)

如果没有此修复,多播发送将间歇性地获取sendto()错误"无主机路由".如果有人能够阐明为什么拔掉DHCP网关会导致Mac OS X多播SENDING套接字混淆,我很乐意听到它.