メッセージを受信する Windows Program

UDP でメッセージを受信する Windows Program を作成します。
送信と違い受信では「ノンブロッキング方式」を使ってタイマ割り込みで受信の確認を行います。

ブロッキングとは、関数の実行が終了するまで、制御が返ってこないことを言います。
例えば recv や accept は、データが受信できるまで制御が戻ってきません。
Windows のプログラムでは、これでは困るのでノンブロッキング方式を使います。

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

プロジェクトの設定

  1. このプログラムは、私が作成した Wsock Object Class を使用します。
    新規プロジェクトを作成して、次のファイルをプロジェクトのフォルダーに格納して下さい。
    ファイル 説明
    Main.cpp メインプログラムファイル
    Wsock.h Wsock Object Class のヘッダファイル
    Wsock.lib Wsock Object Class のライブラリ
  2. ページ先頭の画像を参考に DialogBox を作成して下さい。
    BOX キャプション ID
    DialogBox UDP Receive IDD_DIALOG1
    EditControl PORT番号 IDC_PORT
    EditControl 受信メッセージ IDC_SENDM
    Button 進行メッセージ IDC_MSG
    Button Start UP IDC_STARTUP
    Button Bind IDC_SEND
    Button 終了 IDCANCEL
  3. windows.h をインクルードすると winsock2.h もインクルードされます。
    Wsock.h をインクルードして、ws2_32.lib と Wsock.lib をリンクして下さい。
    ID_TIMER はタイマのID定義です。
    Wsock *App は Wsock Object Class の定義です。
    PORT でポートアドレスを定義します。
    buf[1024] は受信メッセージを格納する領域です。
        /***********************************************/
        /*★ UDP 受信  Wsock Object Class    前田 稔 ★*/
        /***********************************************/
        #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
        int         PORT= 12345;
        char        buf[1024];
        
  4. WinMain() では DialogBox を表示するだけです。
  5. WM_INITDIALOG で Wsock Object Class を生成します。
    EditBox に PORT の規定値を表示します 。
        case WM_INITDIALOG:
            App= new Wsock();
            wsprintf(buf,"%d",PORT);
            SetDlgItemText(hDlg,IDC_PORT,buf);
            break;
        
  6. Start UP ボタンのクリックで Winsock の初期化を行います。
    この操作は受信する前に一度だけ実行します。
        case WM_COMMAND:
            switch(LOWORD(wParam))
            {   case IDC_STARTUP:
                    KillTimer(hDlg, ID_TIMER);
                    App->Startup();
                    SetDlgItemText(hDlg,IDC_MSG,App->szMSG);
                    break;
        
  7. Bind ボタンがクリックされると、タイマ割り込みでメッセージが届く監視を開始します。
    UDPStart(PORT) の実行結果が進行メッセージに表示されます。
    UDP では送信側はメッセージを送るだけなので、何時届いても受信できるように待機しなけれななりません。
    Bind をクリックするとセキュリティの警告が表示されます。
    ファイアウォールに付いては UDP でメッセージを送受信 を参照して下さい。
                case IDC_BIND:
                    PORT= GetDlgItemInt(hDlg,IDC_PORT,NULL,FALSE);
                    if (App->UDPStart(PORT)==0)
                        SetTimer(hDlg, ID_TIMER, 300, NULL);
                    SetDlgItemText(hDlg,IDC_MSG,App->szMSG);
                    break;
        
  8. タイマ割り込みでメッセージが届くのを監視します。
    App->UDPRecv() の戻り値がゼロのときはメッセージが届いたときです。
    転送されたメッセージを表示してから、ソケットを作り直して再接続するために IDC_BIND をポストします。
            case WM_TIMER:
                KillTimer(hDlg, ID_TIMER);
                rc= App->UDPRecv(buf,1024);
                SetDlgItemText(hDlg,IDC_MSG,App->szMSG);
                if (rc==0)
                {   SetDlgItemText(hDlg,IDC_SNDMSG,buf);
                    PostMessage(hDlg,WM_COMMAND,IDC_BIND,(LPARAM)0);
                    break;
                }
                SetTimer(hDlg, ID_TIMER, 300, NULL);
                break;
        
  9. WM_CLOSE では Wsock Object Class を開放して下さい。
            case WM_CLOSE:
                KillTimer(hDlg, ID_TIMER);
                SAFE_DELETE(App);
                EndDialog(hDlg, TRUE); 
                return TRUE;
        

【補足】

Wsock Object Class のノンブロッキングで受信の確認を行うソースコードの抜粋です。
    u_long  val=1;

    // ソケットをバインド
    if (bind(sock,(struct sockaddr *)&addr,sizeof(addr)) != 0)
    {   strcpy(szMSG,"ソケットのバインドに失敗しました");
        return 1;
    }

    // ノンブロッキングに設定しています。
    ioctlsocket(sock, FIONBIO, &val);

    n= recv(sock, buf, sizeof(buf), 0);
    if (n < 1)
    {   if (WSAGetLastError() == WSAEWOULDBLOCK)
        {   // まだ来ない。
            strcpy(szMSG,"Wait");
            return 0;
        }
        strcpy(szMSG,"受信に失敗しました");
        closesocket(sock);
        return -1;
    }

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