この記事では、技術とUDPプロトコルが考慮されないことをすぐに予約してください。このため、UDPを有効にしてからマルチキャストを有効にすることをお勧めします。
したがって、すべての作業は、ソケットの作成とその「構成」から始まります。 一般的にはこのように見えます
1.ソケットを作成する
2.バインドする
3.マルチキャストグループに接続します。
順番に
ソケット作成
すべてがシンプルで、トリックはありません。
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
ソケットバインディング
最初に行う必要があるのは、PORTの再利用を許可することです。 私たちのほかに、他の誰かがこのポートで作業できます。
const int optval = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
setsockopt関数を使用すると、ソケットのオプションを設定できます。 興味深い点は、オプション値がvoidへのポインターによって渡されることです。 一部のオプションでは、on / offフラグだけでなく、追加データを含む構造が必要です。
次に、ソケットをポートに接続する必要があります。 それとも住所ですか? ここに最初の機能機能があります-WindowsとLinuxカーネルの異なるイデオロギーです。 つまり、Windowsでは、マルチキャストグループのアドレスにバインドできず(エラーが発生します)、INADDR_ANYにバインドする必要があります
struct sockaddr_in addr; bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); bind(sockfd, (sockaddr *)&addr, sizeof(addr));
Linuxでは、INADDR_ANYにバインドすることもできますが、この場合、バインドするポートに到達したすべてのデータグラムを受け取ります。 目的のグループからのみデータグラムを受信するには、このグループのアドレスにバインドする必要があります(もちろん、ポートを忘れないでください)。
グループ接続
マルチキャストの主な機能は、マルチキャストグループに接続するまでホストがデータを受信しないことです。 ユーザーレベルの接続は、ソケットのオプションを設定するように見えます。
struct ip_mreq mreq; inet_aton(ip_addr, &(mreq.imr_multiaddr)); mreq.imr_interface.s_addr = htonl(INADDR_ANY); setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
ip_mreq.imr_multiaddrはマルチキャストグループのアドレスです。 また、ip_mreq.imr_interfaceは、データグラムを受信する予定のインターフェイスのアドレスです。 この場合のINADDR_ANYは、この権利をカーネルに任せることを示し、カーネルはルーティングテーブルに基づいてインターフェースを選択します。 次に、カーネルはこのグループに既に接続されているかどうかを確認し、接続されていない場合は、最も近いマルチキャストサーバーに要求を送信します。 さらに次々と、など。 その後、このマルチキャストグループに送信されたデータグラムがホストに送信されます。
しかし、INADDR_ANYにバインドされているWindowsをどうすればよいでしょうか? リスニングポートに送信されたすべてのデータグラムは何を受け取りますか? どうやら、Windowsカーネルは、ソケットにこのオプションを指定すると、受信したデータをフィルタリングします。 したがって、署名されたグループからのデータのみがソケットに配信されます。
Linuxでは、接続されたマルチキャストグループからのみソケットでデータを受信するには、独自のアドレスにバインドする必要があります。
あなたが私を信じないなら(そして私自身も最初はそれを信じていなかった)、彼を信頼しなさい
Unix Network Programming 3エディション。 チャプター21.6ページ599
-マルチキャストデータグラムを受信するには、プロセスはグループに参加し、UDPソケットをポート番号にバインドする必要があります。ポート番号は、このグループに送信されるデータグラムの受信者のポート番号として使用されます。
...
ポートを接続することにより、アプリケーションは、このポートに送信されたデータグラムを受信する必要があることをUDPに示します。 一部のアプリケーションは、ポートバインドに加えて、バインド機能を使用してマルチキャストアドレスをソケットにバインドします。 これにより、ソケットは、このポートで受信された可能性のある他のデータグラムを配信できなくなります。
boost'eはどうですか?
失望しますが、ブーストではすべてがAPIに似ており、単一のロジックへの適応は行われません。 したがって、クロスプラットフォームアプリケーションを作成するためにそれを使用して、まだする必要があります
#ifdef WIN32 boost::asio::ip::udp::endpoint listen_endpoint("0.0.0.0", multicast_port); #else boost::asio::ip::udp::endpoint listen_endpoint(multicast_address, multicast_port); #endif socket_.open(listen_endpoint.protocol()); socket_.set_option(boost::asio::ip::udp::socket::reuse_address(true)); socket_.bind(listen_endpoint); ocket_.set_option(boost::asio::ip::multicast::join_group(multicast_address));
1つのソケットに複数のグループ
投稿を書いているときに、Linuxに提案されたパスが1つの制限を隠していることに気付きました。 1つのソケット-1つのマルチキャストグループの原則に基づいて作業する必要があります。 一度に複数のアドレスをバインドすることはほとんど不可能です。
状況の概要を説明します。 サーバーがあり、複数のマルチキャストグループのデータを1つのポートにブロードキャストします。
クライアントがいて、彼は少数のグループでのみサーバーからデータを受信したいと考えています。 その後、次のアクションを実行する必要があります。
1. INADDR_ANYにバインドする
2.次に、宛先1アドレスを決定することにより、受信したすべてのデータグラムを手動でフィルタリングします。
ソケットで受信したデータグラムを宛先アドレスでフィルタリングするプロセスは、クライアントのマシンに他のグループに接続するが同じポートを持つ別のソフトウェアがあり、両方のソケットがこのポートで接続されているすべてのグループからデータグラムを受信する可能性があるという事実に基づいています。
しかし、同時にデータの冗長性の問題が表面化しています。
まあ、実際にマルチキャストを使用する静かな機能について、私はあなたがレーキを踏む危険性を知らずにあなたに伝えたかったのです。
PS。 これをすべて感じるために、次のステップを実行することを提案します。
1. レシーバーを収集する
2. 送信者を作成する
Linuxの次の実行
3.実行:レシーバー0.0.0.0 239.192.100.1
4.実行:レシーバー0.0.0.0 239.192.100.2
5.実行:センダ239.192.100.1
6.両方の受信者がデータを受信することを確信させるため
次に、Windowsでも実行します
7.データを送信した相手のみがデータを受信するようにしてください。
1 UDPのもう1つの機能は、送信者と受信者のアドレスがUDPメッセージのヘッダーで明示的に示されていないことです。 ただし、カレンダーの計算、つまりUDPデータグラムの受信時に考慮されるため、モジュールは擬似ヘッダーを構成し、盲腸を計算し、受信した盲腸と比較して、データグラムが自分宛であると判断する必要があります。 どうやら、Linuxは宛先としてバインドするアドレスを使用してこのチェックを行うため、上記の