複数のネットワークインターフェイスを持つホスト間でマルチキャストUDPを使用しています。 boost :: asioを使用していますが、受信者が行う必要のある2つの操作、bind、join-groupに混乱しています。
参加するすべてのマルチキャストグループでそれを行うときに、バインド中にインターフェイスのローカルアドレスを指定する必要があるのはなぜですか?
姉妹質問はマルチキャストポートを考慮します:送信中にマルチキャストアドレスとポートに送信するため、マルチキャストグループへのサブスクリプション中に、アドレスではなくアドレスのみを指定します-混同する呼び出しで指定されたポート練る。
注: "join-group"はsetsockopt(IP_ADD_MEMBERSHIP)
のラッパーであり、文書化されているように、同じソケットで複数回呼び出され、異なるグループに(異なるネットワークで?)サブスクライブします。したがって、グループにサブスクライブするたびに、バインドコールを捨ててポートを指定することは完全に理にかなっています。
私が見るところ、常に「0.0.0.0」にバインドし、グループに参加するときにインターフェイスアドレスを指定すると、非常にうまく機能します。混乱した。
マルチキャストの受信時にUDPソケットをバインドするとは、データを受信するアドレスとポートを指定することを意味します(TCPアクセプターバインドの場合のように、ローカルインターフェイスではありません)。この場合、指定されたアドレスにはフィルタリングの役割があります。つまり、ソケットは、その後どのグループがソケットに参加しても、そのマルチキャストアドレスとポートに送信されたデータグラムのみを受信します。これは、INADDR_ANY(0.0.0.0)にバインドすると、マルチキャストグループに送信されたデータグラムを受信したのに対し、ローカルインターフェイスにバインドすると、データグラムがそのインターフェイスに送信されていても何も受信しなかった理由を説明します対応しました。
UNIX®Network Programming Volume 1、Third Edition:The Sockets Networking API by W.R Stevensから引用21.10。送信と受信
[...]受信ソケットに239.255.1.2ポート8888などのマルチキャストグループとポートをバインドさせます(ワイルドカードIPアドレスとポート8888だけをバインドできますが、マルチキャストアドレスをバインドするとソケットが受信できなくなることを思い出してくださいポート8888宛てに到着する可能性のある他のデータグラム。)次に、受信ソケットをマルチキャストグループに参加させます。送信ソケットは、この同じマルチキャストアドレスとポート、たとえば239.255.1.2ポート8888にデータグラムを送信します。
「バインド」操作は、基本的に「このローカルUDPポートを使用してデータを送受信します。つまり、そのUDPポートをアプリケーション専用に割り当てます。(TCPソケットにも同じことが当てはまります。 )。
"0.0.0.0"( INADDR_ANY
)にバインドすると、基本的にTCP/IPレイヤーに、使用可能なすべてのアダプターを使用してリッスンし、送信に最適なアダプターを選択するよう指示します。これは、ほとんどのソケットコードの標準的な方法です。 IPアドレスに0を指定しないのは、特定のネットワークアダプターで送受信する場合のみです。
同様に、バインド中にポート値0を指定すると、OSはそのソケットにランダムに使用可能なポート番号を割り当てます。したがって、UDPマルチキャストの場合、マルチキャストトラフィックの送信先となる特定のポート番号のINADDR_ANYにバインドすることになります。
「マルチキャストグループへの参加」操作(IP_ADD_MEMBERSHIP
)が必要なのは、基本的にネットワークアダプタに、宛先MACアドレスが自分のものであるイーサネットフレームだけでなく、イーサネットアダプタにも指示するよう指示するためです( NIC )IPマルチキャストトラフィックおよび対応するマルチキャストイーサネットアドレスもリッスンします。各マルチキャストIPは、マルチキャストイーサネットアドレスにマップされます。ソケットを使用して特定のマルチキャストIPに送信する場合、イーサネットフレームの宛先MACアドレスは、マルチキャストIPの対応するマルチキャストMACアドレスに設定されます。マルチキャストグループに参加すると、(同じNICアドレスに加えて)その同じMACアドレスに送信されたトラフィックをリッスンするようにNICを構成します。
ハードウェアのサポートがなければ、マルチキャストは単なるブロードキャストIPメッセージよりも効率的ではありません。また、参加操作は、他のネットワークからのマルチキャストトラフィックを転送するようルーター/ゲートウェイに指示します。 (MBONEを覚えている人はいますか?)
マルチキャストグループに参加すると、そのIPアドレスのすべてのポートのすべてのマルチキャストトラフィックがNICによって受信されます。バインドされたリスニングポート宛てのトラフィックのみが、TCP/IPスタックを介してアプリに渡されます。マルチキャストサブスクリプション中にポートが指定される理由に関して-マルチキャストIPはまさにそのため-IPのみ。 「ポート」は、上位プロトコル(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)ソケットをバインドするとはどういう意味ですか? 以下の引用で部分的に当てはまる場合の修正:
「バインド」操作は、基本的に「データの送受信にこのローカルUDPポートを使用します。つまり、exclusiveアプリケーションで使用
例外が1つあります。 SO_REUSEADDR
オプションが適用されている場合、複数のアプリケーションcanはリスニング用に同じポートを共有します(通常、マルチキャストデータグラムに実用的な値を持っています)。例えば
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データグラムは各プロセスに配信されます(マルチキャストトラフィックとの自然な結合を提供します)。
いくつかのケースで何が起こるかについてさらに詳しく説明します。
空きポートへのバインド(「排他的」または「再利用」)の試行は成功します。
ポートがすでに「再利用バインド」されている場合、「排他的バインド」の試行は失敗します
一部のプロセスが「排他的バインディング」を保持している場合、「バインディングの再利用」の試行は失敗します
SENDINGマルチキャストソケットとRECEIVINGマルチキャストソケットを区別することも非常に重要です。
マルチキャストソケットの受信に関する上記のすべての回答に同意します。 OPは、受信ソケットをインターフェイスにバインドしても役に立たないと指摘しました。ただし、マルチキャスト送信ソケットをインターフェイスにバインドする必要があります。
マルチホームサーバー上のSENDINGマルチキャストソケットの場合、veryは、送信先のインターフェイスごとに個別のソケットを作成することが重要です。バインドされた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 'No route to Host'を取得します。 DHCPゲートウェイのプラグを抜くとMac OS Xマルチキャスト送信ソケットが混乱する原因を解明できる人がいたら、ぜひ聞いてみてください。