Peer to Peer でメッセージの送受信

Peer to Peer で接続して、リアルタイムにメッセージを送受信するプログラムを作成します。
LAN で接続されているマシンを繋いでテストします。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの設定

  1. このプログラムは Wsock Object Class(私有ライブラリ)を使って DialogBox ベースで作成します。
    新規プロジェクトを作成して、次のファイルをプロジェクトのフォルダーに格納して下さい。
    ファイル 説明
    Main.cpp メインプログラムファイル
    Wsock.h Wsock Object Class のヘッダファイル
    Wsock.lib Wsock Object Class のライブラリ
  2. ページ先頭の画像を参考に DialogBox を作成して下さい。
    BOX キャプション ID
    DialogBox UDP Receive IDD_DIALOG1
    EditControl 受信PORT IDC_RPORT
    EditControl 送信PORT IDC_SPORT
    EditControl 送信URL IDC_URL
    EditControl 受信メッセージ IDC_SENDM
    EditControl IDC_LOG
    Button Start UP IDC_STARTUP
    Button 終了 IDCANCEL
    Button Send IDC_SEND
  3. Wsock.h をインクルードして、ws2_32.lib と Wsock.lib をリンクして下さい。
    ID_TIMER はタイマのID定義です。
    Wsock *App は Wsock Object Class の定義です。
    URL と SPORT で送信先を設定します。
    RPORT でメッセージの受信を監視するポートを設定します。
    log[60000] は送信メッセージと受信メッセージのログを記録する領域です。
    buf[1024] は受信メッセージを格納する領域です。
        /**************************************/
        /*★ UDP メッセージ交換     前田 稔 ★*/
        /**************************************/
        #include    <windows.h>
        #include    "Wsock.h"
        #include    "resource.h"
        #pragma     once
        #pragma     comment(lib,"ws2_32.lib")
        #pragma     comment(lib,"Wsock.lib")
        #define     ID_TIMER    32767
    
        Wsock       *App= NULL;                 //Wsock Object Class
        char        URL[MAX_PATH]= "127.0.0.1"; //送信先 URL
        int         SPORT= 12345;               //送信先 PORT
        int         RPORT= 12345;               //受信 PORT
    
        char        log[60000];                 //Message Log
        char        buf[1024];
        
  4. WinMain() では DialogBox を表示するだけです。
  5. WM_INITDIALOG で Wsock Object Class を生成します。
    EditBox に URL と PORT の規定値を表示します 。
        case WM_INITDIALOG:
            App= new Wsock();
            SetDlgItemText(hDlg,IDC_URL,URL);
            wsprintf(buf,"%d",SPORT);
            SetDlgItemText(hDlg,IDC_SPORT,buf);
            wsprintf(buf,"%d",RPORT);
            SetDlgItemText(hDlg,IDC_RPORT,buf);
            break;
        
  6. Start UP ボタンのクリックで Winsock の初期化を行います。
    App->UDPStart() でソケットを Bind してタイマ割り込みで到着メッセージの監視を始めます。
    受信のIPアドレスは INADDR_ANY(誰でもいいから)に設定されています。
    UDP では送信側はメッセージを送るだけなので、何時届いても受信できるように待機しなけれななりません。
    この操作は送受信する前に一度だけ実行します。
    クリックするとセキュリティの警告が表示されます。
    ファイアウォールに付いては UDP でメッセージを送受信 を参照して下さい。
        case WM_COMMAND:
            switch(LOWORD(wParam))
            {   case IDC_STARTUP:
                    KillTimer(hDlg, ID_TIMER);
                    App->Startup();
                    RPORT= GetDlgItemInt(hDlg,IDC_RPORT,NULL,FALSE);
                    if (App->UDPStart(RPORT)==0)
                        SetTimer(hDlg, ID_TIMER, 300, NULL);
                    strcpy(log,App->szMSG);
                    strcat(log,"\r\n");
                    SetDlgItemText(hDlg,IDC_LOG,log);
                    break;
        
  7. メッセージが届くとソケットが削除されるので、新しいソケットを生成して再度 Bind します。
                case IDC_BIND:
                    RPORT= GetDlgItemInt(hDlg,IDC_RPORT,NULL,FALSE);
                    if (App->UDPStart(RPORT)==0)
                        SetTimer(hDlg, ID_TIMER, 300, NULL);
                    break;
        
  8. 送信ボタンをクリックすると「URL と送信 PORT」で指定された相手先に送信メッセージを送ります。
    送信先はボタンをクリックする直前に自由に変更することが出来ます。
    UDP では相手先に届いたか否かには関知せず、単にメッセージを送信するだけです。
    画面に送信記録が表示されますが、相手が受け取った保障はありません。
                case IDC_SEND:
                    GetDlgItemText(hDlg,IDC_URL,URL,MAX_PATH);
                    SPORT= GetDlgItemInt(hDlg,IDC_SPORT,NULL,FALSE);
                    GetDlgItemText(hDlg,IDC_SENDM,buf,1024);
                    App->UDPSend(URL,SPORT,buf);
                    strcat(log,"送信: ");
                    strcat(log,buf);
                    strcat(log,"\r\n");
                    SetDlgItemText(hDlg,IDC_LOG,log);
                    break;
        
  9. タイマ割り込みでメッセージが届くのを監視します。
    App->UDPRecv() の戻り値がゼロのときはメッセージが届いたときです。
    受信したメッセージを LOG に格納してから、ソケットを作り直して再接続するために IDC_BIND をポストします。
            case WM_TIMER:
                KillTimer(hDlg, ID_TIMER);
                rc= App->UDPRecv(buf,1024);
                if (rc==0)
                {   strcat(log,"受信: ");
                    strcat(log,buf);
                    strcat(log,"\r\n");
                    SetDlgItemText(hDlg,IDC_LOG,log);
                    PostMessage(hDlg,WM_COMMAND,IDC_BIND,(LPARAM)0);
                    break;
                }
                SetTimer(hDlg, ID_TIMER, 300, NULL);
                break;
        
  10. WM_CLOSE では Wsock Object Class を開放して下さい。
            case WM_CLOSE:
                KillTimer(hDlg, ID_TIMER);
                SAFE_DELETE(App);
                EndDialog(hDlg, TRUE); 
                return TRUE;
        
  11. C# を使って同じようなプログラムを開発しています。
    C# の方が簡単に作成出来ることを確かめて下さい。
    IPアドレスを指定して送信/受信

プログラムのテスト

  1. 最初に一本のプログラムでテストしてみましょう。
    1. プログラムを立ち上げて、次の値に設定して下さい。
      127.0.0.1 は自分自身を指すIPアドレスです。
      受信Port 12345
      送信Port 12345
      送信URL 127.0.0.1
    2. Start UP ボタンをクリックして、待機状態に設定して下さい。
    3. 「送信メッセージ」に "Hello" をタイプして Send ボタンをクリックします。
      Log の TextBox に「送信: Hello」と「受信: Hello」が表示されます。
    4. 送信メッセージに "メッセージを送信します" をタイプして Send ボタンをクリックしてみて下さい。
    5. 終了ボタンをクリックするとプログラムが終了します。
  2. 1台のマシンで二本のプログラムを立ち上げてテストします。
    1. 一本目のプログラムを立ち上げて、次の値に設定して下さい。
      127.0.0.1 は自分自身を指すIPアドレスです。
      受信Port 12345
      送信Port 12340
      送信URL 127.0.0.1
    2. Start UP ボタンをクリックして、待機状態に設定して下さい。
    3. 二本目のプログラムを立ち上げて、次の値に設定して下さい。
      一本目も二本目もこのページで作成した同じプログラムです。
      Port は一本目の送信が二本目の受信になり、一本目の受信が二本目の送信になります。
      受信Port 12340
      送信Port 12345
      送信URL 127.0.0.1
    4. 二本目の Start UP ボタンをクリックして下さい。
    5. 二本目の「送信メッセージ」に Hello をタイプして Send ボタンをクリックします。
      「送信: Hello」が表示されて、12345 のポートにメッセージが送信されます。
    6. 一本目のプログラムに「受信: Hello」が表示されたらOKです。
    7. 同じ要領で一本目のプログラムから返信して下さい。
      こんどは一本目に「送信:メッセージ」が表示され、二本目に「受信:メッセージ」が表示されます。
  3. LAN で接続されている2台のマシンでテストしてみましょう。
    1. 最初にそれぞれのパソコンのIPアドレスを調べて下さい。
      パソコンに割り当てられたIPアドレスは ipconfig で確認できます。
      C:\>ipconfig
    2. 1台目のプログラムを立ち上げて、次の値に設定して下さい。
      169.180.32.52 は私がテストしたときの2台目のIPアドレスです。
      送信メッセージは、1台目のパソコンから2台目のパソコンに送信します。
      受信Port 12345
      送信Port 12340
      送信URL 169.180.32.52
    3. Start UP ボタンをクリックして、待機状態に設定して下さい。
    4. 2台目のプログラムを立ち上げて、次の値に設定して下さい。
      起動するプログラムは、このページで説明している同じプログラムです。
      Port は1台目の送信が2台目の受信になります。
      192.254.198.113 は私がテストしたときの1台目のIPアドレスです。
      送信メッセージは、2台目のパソコンから1台目のパソコンに送信します。
      受信Port 12340
      送信Port 12345
      送信URL 192.254.198.113
    5. 2台目の「送信メッセージ」に Hello をタイプして Send ボタンをクリックします。
      「送信: Hello」が表示されて、192.254.198.113 の 12345 にメッセージが送信されます。
    6. 1台目のマシンにメッセージが送信されて「受信: Hello」が表示されたらOKです。
  4. 3台以上のマシンを接続して、相互に通信することも出来ます。
    そのときは送信側と受信側のIPアドレスとポートを矛盾しないように設定して下さい。

【NOTE】

  1. インターネットでは、コンピュータ同士がインターネットプロトコル(IP)を使って通信を行います。
    IPアドレスにはいくつかの特別な番号があります。
    1. INADDR_ANY (0.0.0.0)
      誰でもいいから
    2. INADDR_LOOPBACK (127.0.0.1)
      自分自身(というか、ネットワークに出さずに折り返し)
    3. INADDR_BROADCAST (255.255.255.255)
      ネットワークに繋がっている全コンピュータ
    4. INADDR_NONE (255.255.255.255) 存在しない
    INADDR_BROADCAST と INADDR_NONE は同じ値ですが、使用する状況で意味が異なります。
  2. 二台のパソコンを使って相互に通信するときは、パソコンに割り当てられたIPアドレスを調べて設定して下さい。
    パソコンに割り当てられたIPアドレスは ipconfig で確認できます。
    DNS(Domain Name Service) を使っている時などは、IPアドレスが変わることがあるので、実行時に確認して下さい。
    C:\>ipconfig
  3. ネット接続されていることを確認するときは ping が通ることを確認します。
    例えば使用中のマシンが 192.180.32.51 と接続されていることを確認するときは、次のようにタイプします。
    C:\>ping 192.180.32.51
  4. ポートの設定
    IP アドレスを使ってコンピュータを指定して、ポートを使ってアプリケーションを指定します。
    電子メールサーバー、Webサーバー、FTPサーバーといった皆が接続にくるようなアプリケーションサーバー(サービス)はその種類によって、決まったポートで待っています。
    例えば、電子メールの送信なら25番、受信が110番、FTPなら21番です。
    独自のネットワークサービスプログラムを作るのならこれらの番号以外を選ばなければなりません。
    一般的なテスト用には、5000番や12345番や9999番などが良く使われます。

超初心者のプログラム入門(Win32API C++)