Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets 绑定多播(UDP)套接字意味着什么?_Sockets_Udp_Bind_Boost Asio_Multicast - Fatal编程技术网

Sockets 绑定多播(UDP)套接字意味着什么?

Sockets 绑定多播(UDP)套接字意味着什么?,sockets,udp,bind,boost-asio,multicast,Sockets,Udp,Bind,Boost Asio,Multicast,我在具有多个网络接口的主机之间使用多播UDP。 我使用的是boost::asio,我对接收器必须执行的两个操作感到困惑:绑定,然后加入组 在绑定期间,当您对加入的每个多播组进行绑定时,为什么需要指定接口的本地地址 姐妹问题涉及多播端口:因为在发送期间,您发送到多播地址和端口,为什么在订阅多播组期间,您只指定地址,而不指定端口-在绑定调用中指定的端口 注意:“加入组”是setsockopt(IP\u ADD\u MEMBERSHIP)上的包装器,如文档所述,可以在同一套接字上多次调用它以订阅不同的

我在具有多个网络接口的主机之间使用多播UDP。 我使用的是boost::asio,我对接收器必须执行的两个操作感到困惑:绑定,然后加入组

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

姐妹问题涉及多播端口:因为在发送期间,您发送到多播地址和端口,为什么在订阅多播组期间,您只指定地址,而不指定端口-在绑定调用中指定的端口

注意:“加入组”是
setsockopt(IP\u ADD\u MEMBERSHIP)
上的包装器,如文档所述,可以在同一套接字上多次调用它以订阅不同的组(通过不同的网络?)。因此,放弃bind调用并在每次订阅组时指定端口是非常有意义的

在我看来,加入组时总是绑定到“0.0.0.0”并指定接口地址,效果非常好。困惑。

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

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

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

需要“加入多播组”操作(
IP\u ADD\u MEMBERSHIP
),因为它基本上告诉您的网络适配器不仅要侦听目标MAC地址为您自己的以太网帧,还告诉以太网适配器()侦听IP多播通信以及相应的多播以太网地址。每个多播IP映射到一个多播以太网地址。当您使用套接字发送到特定的多播IP时,以太网帧上的目标MAC地址设置为多播IP的相应多播MAC地址。当您加入在多播组中,您正在配置NIC以侦听发送到同一MAC地址的通信量(除了自己的MAC地址之外)

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

如果您加入一个多播组,NIC将接收该IP地址上所有端口的所有多播流量。只有绑定到您的侦听端口的流量将通过TCP/IP堆栈传递到您的应用程序。关于在多播订阅期间指定端口的原因,这是因为多播IP只是-仅限IPy、 “端口”是上层协议(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位


接收多播时绑定UDP套接字意味着指定从中接收数据的地址和端口(而不是本地接口,如TCP接受器绑定)。本例中指定的地址具有过滤作用,即套接字仅接收发送到该多播地址和端口的数据报,而不管套接字随后加入了哪些组。这解释了为什么绑定到INADDR_ANY(0.0.0.0)时我收到了发送到我的多播组的数据报,而当绑定到任何本地接口时,我没有收到任何东西,即使数据报是在该接口对应的网络上发送的

引自UNIX®网络编程第1卷第三版:W.R Stevens的Sockets Networking API。 21.10.发送和接收

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

只要以下报价部分正确,则进行更正:

“绑定”操作基本上是说,“使用这个本地UDP端口发送和接收数据。换句话说,它将该UDP端口分配给应用程序的独占使用

有一个例外。如果应用了
SO\u 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数据报都将被传递到每个进程(提供与多播通信的自然连接)

以下是有关少数情况下发生的情况的更多详细信息:

  • <
      // 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) );
         }