Visual C++LAN IPマルチキャストを実現


ローカルエリアネットワークでは、管理者は常にユーザーのグループに情報を送信する必要があります.一対一の発送方法を使えば、可能ですが、面倒すぎて、漏れやミスもよくあります.このようなグループ通信の問題をより効果的に解決するために、IP層ベースの通信技術であるマルチキャスト技術(マルチキャスト通信とも呼ばれることが多い)が出現した.読者の理解を助けるために、マルチキャストの概念を簡単に紹介します.
周知のように、通常のIP通信は1つの送信者と1つの受信者の間で行われ、私たちはよくそれを点対点の通信と呼ぶが、一部のアプリケーションでは、このような点対点の通信モードは実際のアプリケーションのニーズを効果的に満たすことができない.例えば、1つのデジタル電話会議システムは、複数の会場から構成され、そのうちの1つの会場の参加者が発言する場合、他の会場にこの発言の内容を即時に得るように要求される.これは典型的な1対多の通信アプリケーションであり、通常、このような1対多の通信をマルチキャスト通信と呼ぶ.マルチキャスト通信技術を採用することで、1つの送信者と複数の受信者との間で通信を行う機能を実現できるだけでなく、ネットワーク通信の負担を効果的に軽減し、資源の無駄を避けることができる.
ブロードキャストも1対のマルチデータ通信を実現するモードであるが、ブロードキャストとマルチキャストは実現方式が異なる.ブロードキャストは、1つのワークステーションからデータを送信し、ローカルエリアネットワーク内の他のすべてのワークステーションで受信できます.この特徴は、LAN上のすべての機器がブロードキャストメッセージを取得して処理できるため、無接続プロトコルに適用される.ブロードキャストメッセージの使用の不利な点は、各マシンがメッセージを処理しなければならないことである.マルチキャスト通信とは異なり、1つのワークステーションからデータが送信された後、他のLAN上のマシン上で実行されるプロセスがこれらのデータに「興味がある」ことを示すと、マルチキャストデータが作成されます.
この例は、SenderとReceiverの2つのプログラムからなり、Senderユーザはコンソールからマルチキャスト送信データを入力し、Receiver側は同じマルチキャストグループに参加し、Senderが送信したマルチキャストデータの受信を完了するように要求する.
一、実現方法
1、協議サポート
すべてのプロトコルがマルチキャスト通信をサポートしているわけではありません.Win 32プラットフォームでは、WinSockからアクセス可能な2つのプロトコル(IP/ATM)のみがマルチキャスト通信をサポートします.通常、通信アプリケーションはTCP/IPプロトコルに基づいているため、本稿ではIPプロトコルについてマルチキャスト通信技術のみを検討する.
マルチキャスト通信をサポートするプラットフォームは、Windows CE 2.1、Windows 95、Windows 98、Windows NT 4、Windows 2000、WindowsXPを含む.バージョン2.1から、Windows CEはIPマルチキャストのサポートを開始しました.この例は、WindowsXPプロフェッショナル版プラットフォームに構築されています.
2、マルチキャストアドレス
IPはDクラスアドレスを用いてマルチキャストをサポートする.各Dクラスアドレスはホストのセットを表します.グループを識別するために28ビット使用できます.25億のグループを同時に持つことができますプロセスがDクラスアドレスにパケットを送信する場合、グループのすべてのメンバーに送信するように最善を尽くしますが、すべてが送信されることは保証されません.一部のメンバーはこのグループを受け取れない可能性があります.例えば、5つのノードがI Pマルチキャストによって相互間の通信を実現したいと仮定すると、それらは同じグループアドレスに参加することができる.すべてが追加されると、1つのノードから送信された任意のデータがそっくりコピーされ、グループ内の各メンバーに送信され、始発データを含むノードに送信されます.DクラスI Pアドレス範囲は244.0.0.0から239.255.255.255の間である.永続アドレスと一時アドレスの2つに分類されます.永続アドレスは特殊な用途のために保持されます.たとえば、244.0.0.0はまったく使用されていません(使用できません)、244.0.0.1はサブネット内のすべてのシステム(ホスト)を表し、244.0.0.2はサブネット内のすべてのルータを表します.RFC 1700ファイルには、すべての予約アドレスの詳細リストが提供される.このファイルは、特殊な用途のために保持されているすべてのリソースのリストであり、参考にすることができます.「インターネット配信デジタルエキスパートグループ」(I A N A)がこのリストのメンテナンスを担当しています.表1では,現在「予約」と表記されているアドレスのいくつかをまとめた.テンポラリ・グループ・アドレスは、使用前に作成する必要があります.プロセスは、ホストに特定のグループに参加するように要求したり、ホストがグループから離れるように要求したりすることができます.ホスト上の最後のプロセスがグループから離れると、そのグループのアドレスはこのホストに表示されなくなります.各ホストは、プロセスが現在どのグループに属しているかを記録します.表1の永続アドレスの説明:
 
アドレス
説明
244.0.0.1
きほんアドレス
244.0.0.1
サブネット上のすべてのシステム
244.0.0.2
サブネット上のすべてのルータ
244.0.0.5
サブネット上のすべてのOSPFルータ
244.0.0.6
サブネット上のすべての指定されたOSPFルータ
244.0.0.9
RIP第2バージョングループアドレス
244.0.1.1
ネットワーク時間プロトコル
244.0.1.24
WINSサーバグループアドレス
3、マルチキャストルータ
マルチキャストは特殊なマルチキャストルータによって実現され、マルチキャストルータは通常のルータでもある.各マルチキャストルータは、サブネット上のホスト(宛先アドレス244.0.0.1)に、プロセスが現在所属しているグループを報告し、各ホストが興味のあるDクラスアドレスを返すように、1分ごとにハードウェアマルチキャスト情報を送信する.これらの問い合わせ及び応答パケットは、ICMPとほぼ同様のIGMP(Internet group Management protocol)を用いる.質問と応答の2つのパケットしかありません.単純な固定フォーマットがあり、ペイロードフィールドの最初のフィールドはいくつかの制御情報であり、第2のフィールドはDクラスアドレスであり、RFC 112で詳細に説明されています.
マルチキャストルータの選択は、各マルチキャストルータが修正された距離ベクトルプロトコルを用いてその隣接者と情報を交換し、各ルータにすべてのグループのためにすべてのグループをカバーする生成ツリーを構築するために、ツリーを生成することによって実現される.生成ツリーをトリミングしたり、関係のないルータやネットワークを削除したりする際に、多くの最適化方法が使用されています.
4、ライブラリサポート
WinSockはマルチキャスト通信を実現するAPI関数呼び出しを提供する.IPマルチキャストに対して、WinSockはどのバージョンのWinSockを使用するかによって、2つの異なる実現方法を提供する.第1の方法はWinSock 1が提供し、ソケットオプションによってグループに参加することを要求する.もう1つの方法はWinSock 2が提供したもので、それは新しい関数を導入して、マルチキャストグループの参加を専門に担当して、この関数はWSAJoinLeafで、それは末端プロトコルは関係ありません.本稿では、マルチキャスト通信の一例の実装プロセスにより、マルチキャスト実装の主なステップについて説明する.Window 98以降はWinsock 2がインストールされているため.0以上のバージョンであるため、本明細書の例はWinSock 2である.0プラットフォーム上で開発されたが,その中でWinSock 1が実現する異なる点について説明する.
二、プログラミング手順
1、Visual C++6.0を起動し、コンソールプロジェクトプロジェクトMultiCaseを作成する.このプロジェクトプロジェクトにSenderとReceiverの2つのプロジェクトを追加します.Receiverプロジェクトの実装手順:
(1)、SOCK_を作成するDGRAMタイプのSocket.
(2)、サーバ側から送信されたマルチキャストデータを受信するために、このSocketをローカルの1つのポートにバインドする.
(3)、マルチキャストグループに加入する.
①、WinSock 2にWSAJoinLeafを導入し、この関数の原型は以下の通りである.
 SOCKET WSAJoinLeaf( SOCKET s, const struct sockaddr FAR *name, int namelen, LPWSABUF lpCallerData, LPWSABUF lpCalleeData, LPQOS lpSQOS,

LPQOS lpGQOS, DWORD dwFlags );


ここで、最初のパラメータsは、WSASOcketから返されるソケットハンドルを表す.伝わるこのソケット
字は適切なマルチキャストフラグを使用して作成しなければならない.そうでなければWSAJoinLeafは失敗し、エラーWSASINVALを返します.2番目のパラメータはSOCKADDR(ソケットアドレス)構造であり、具体的な内容は現在採用されているプロトコルによって決定され、IPプロトコルにとって、このアドレスはホストが加入しようとするマルチキャストグループを指定する.3番目のパラメータnamelen(名前の長さ)は、バイト単位でnameパラメータの長さを指定するために使用されます.4番目のパラメータlpCallerData(発信者データ)の役割は、セッションが確立された後、1つのデータバッファを自分の通信相手に転送することである.5番目のパラメータlpCalleeData(被呼者データ)は、セッションが作成された後、相手からのデータを受信するバッファを初期化するために使用されます.現在のWindowsプラットフォームでは、lpCallerDataとlpCalleeDataの2つのパラメータは実際に実装されていないため、NULLに設定する必要があります.LpSQOSとlpGQOSの2つのパラメータはQoS(サービス品質)に関する設定であり、通常はNULLにも設定されているが、QoSの内容についてはMSDNまたは関連書籍を参照してください.最後のパラメータdwFlagsは、ホストがデータの送信、データの受信、または送受信の統合であることを示す.このパラメータのオプション値は、JL_です.SENDER_ONLY、JL_RECEIVER_ONLYまたはJL_BOTH.
②、WinSock 1プラットフォームにマルチキャストグループを追加するにはsetsockopt関数を呼び出し、IP_を設定する必要があるADD_MEMBERSHIPオプションで、加入したいグループのアドレス構造を指定します.具体的なインプリメンテーションコードは、次のコードコメントにリストされます.
 
(4)、マルチキャストデータを受信する.
2、Sender実装手順:
(1)、SOCK_を作成するDGRAMタイプのSocket.
(2)、マルチキャストグループに加入する.
(3)、マルチキャストデータを送信する.
3、2つのプロジェクトをコンパイルし、ローカルエリアネットワークで以下の手順でテストする.
(1)、Sender.exeはマルチキャストデータを送信するPCにコピーする.
(2)、Receiver.exeは、マルチキャストデータの受信を要求する複数のPCにコピーされる.
(3)、それぞれに対応するプログラムを実行する.
(4)、Sender PCにマルチキャストデータを入力すると、Receiver PCに入力したマルチキャストデータが表示されます.
三、プログラムコード
    Receiver.cプログラムコード
 

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#define MCASTADDR "233.0.0.1" // 。
#define MCASTPORT 5150 // 。
#define BUFSIZE 1024 // 。
int main( int argc,char ** argv)
{
 WSADATA wsd;
 struct sockaddr_in local,remote,from;
 SOCKET sock,sockM;
 TCHAR recvbuf[BUFSIZE];
 /*struct ip_mreq mcast; // Winsock1.0 */

 int len = sizeof( struct sockaddr_in);
 int ret;
 // WinSock2.2
 if( WSAStartup( MAKEWORD(2,2),&wsd) != 0 )
 {
printf("WSAStartup() failed/n");
return -1;
 }
 /*
  SOCK_DGRAM SOCKET
  ,WSA_FLAG_MULTIPOINT_C_LEAF IP " " ;
 WSA_FLAG_MULTIPOINT_D_LEAF IP " ",
  MSDN 。
 */
 if((sock=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,
WSA_FLAG_MULTIPOINT_C_LEAF|WSA_FLAG_MULTIPOINT_D_LEAF|
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
 {
printf("socket failed with:%d/n",WSAGetLastError());
WSACleanup();
return -1;
 }
 // sock 。
 local.sin_family = AF_INET;
 local.sin_port = htons(MCASTPORT);
 local.sin_addr.s_addr = INADDR_ANY;
 if( bind(sock,(struct sockaddr*)&local,sizeof(local)) == SOCKET_ERROR )
 {
printf( "bind failed with:%d /n",WSAGetLastError());
closesocket(sock);
WSACleanup();
return -1;
 }
 //
 remote.sin_family = AF_INET;
 remote.sin_port = htons(MCASTPORT);
 remote.sin_addr.s_addr = inet_addr( MCASTADDR );
 /* Winsock1.0 */
 /*
 mcast.imr_multiaddr.s_addr = inet_addr(MCASTADDR);
 mcast.imr_interface.s_addr = INADDR_ANY;
 if( setsockopt(sockM,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&mcast,

sizeof(mcast)) == SOCKET_ERROR)
 {
printf("setsockopt(IP_ADD_MEMBERSHIP) failed:%d/n",WSAGetLastError());
closesocket(sockM);
WSACleanup();
return -1;
 }
 */
 /* Winsock2.0*/
 if(( sockM = WSAJoinLeaf(sock,(SOCKADDR*)&remote,sizeof(remote),

NULL,NULL,NULL,NULL,
JL_BOTH)) == INVALID_SOCKET)
 {
printf("WSAJoinLeaf() failed:%d/n",WSAGetLastError());
closesocket(sock);
WSACleanup();
return -1;
 }
 // , "QUIT" 。
 while(1)
 {
if(( ret = recvfrom(sock,recvbuf,BUFSIZE,0,

(struct sockaddr*)&from,&len)) == SOCKET_ERROR)
{
 printf("recvfrom failed with:%d/n",WSAGetLastError());
 closesocket(sockM);
 closesocket(sock);
 WSACleanup();
 return -1;
}
if( strcmp(recvbuf,"QUIT") == 0 ) break;
else {
 recvbuf[ret] = '/0';
 printf("RECV:' %s ' FROM <%s> /n",recvbuf,inet_ntoa(from.sin_addr));
}
 }

 closesocket(sockM);
 closesocket(sock);
 WSACleanup();
 return 0;
}


    Sender.cプログラムコード
 

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#define MCASTADDR "233.0.0.1" // 。
#define MCASTPORT 5150 // 。
#define BUFSIZE 1024 // 。
int main( int argc,char ** argv)
{
 WSADATA wsd;
 struct sockaddr_in remote;
 SOCKET sock,sockM;
 TCHAR sendbuf[BUFSIZE];
 int len = sizeof( struct sockaddr_in);
 // WinSock2.2
 if( WSAStartup( MAKEWORD(2,2),&wsd) != 0 )
 {
printf("WSAStartup() failed/n");
return -1;
 }
 if((sock=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,
WSA_FLAG_MULTIPOINT_C_LEAF|WSA_FLAG_MULTIPOINT_D_LEAF|
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
 {
printf("socket failed with:%d/n",WSAGetLastError());
WSACleanup();
return -1;
 }
 //
 remote.sin_family = AF_INET;
 remote.sin_port = htons(MCASTPORT);
 remote.sin_addr.s_addr = inet_addr( MCASTADDR );
 if(( sockM = WSAJoinLeaf(sock,(SOCKADDR*)&remote,
sizeof(remote),NULL,NULL,NULL,NULL,
JL_BOTH)) == INVALID_SOCKET)
 {
printf("WSAJoinLeaf() failed:%d/n",WSAGetLastError());
closesocket(sock);
WSACleanup();
return -1;
 }

 // , "QUIT" 。
 while(1)
 {
printf("SEND : ");
scanf("%s",sendbuf);
if( sendto(sockM,(char*)sendbuf,strlen(sendbuf),0,(struct sockaddr*)

&remote,sizeof(remote))==SOCKET_ERROR)
{
 printf("sendto failed with: %d/n",WSAGetLastError());
 closesocket(sockM);
 closesocket(sock);
 WSACleanup();
 return -1;
}
if(strcmp(sendbuf,"QUIT")==0) break;
Sleep(500);
 }

 closesocket(sockM);
 closesocket(sock);
 WSACleanup();
 return 0;
}


四、まとめ
本例では,IPマルチキャスト通信について検討したが,インスタンスプログラムはSenderとReceiverの2つの部分からなり,Senderユーザはコンソールからマルチキャスト送信データを入力し,Receiver側はいずれも同じマルチキャストグループに参加し,Senderが送信したマルチキャストデータの受信を完了することを要求した.