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位可用以太网地址空间.
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数据报都将被传递到每个进程(提供与多播流量的自然联合).
以下是有关在少数情况下会发生什么的更多细节:
尝试任何绑定("独占"或"重用")到自由端口将成功
如果端口已经"重用绑定",尝试"独占绑定"将失败
如果某些进程保持"独占绑定",尝试"重用绑定"将失败
将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套接字混淆,我很乐意听到它.
归档时间: |
|
查看次数: |
99117 次 |
最近记录: |