TCP/IPプログラムのいろはは、DOS窓でWinSockAPI

|

Windowsアプリケーション間で、データの遣り取りをするにはどうすれば良いのか調べてみると、「クリップボード」や「パイプ」、「ソケット通信」、「共有メモリ」など、複数有ることが分かりました。

その中でも今回は、一番(?)取っつき易そうな「ソケット通信」を試してみる事に。

試しに、WinSockAPIでソケット通信の準備と整理を行うだけのサンプルを作ってみました。

printf("IP = %d.%d.%d.%d\n", (BYTE)*(host->h_addr_list[i]), (BYTE)*((host->h_addr_list[i]) + 1), (BYTE)*((host->h_addr_list[i]) + 2), (BYTE)*((host->h_addr_list[i]) + 3));

printf("IP = %s\n", inet_ntoa(*(IN_ADDR *)host->h_addr_list[i]));

上の2つの printf は、どちらも同じ結果を出力します。分かり易い(ピンときた)方を選ぶと良いかも。

・コマンドの引数にローカル指定だけでなく、ヤフーやグーグルなどの外部指定も動作する事を確認しています。


<注意点>

・プログラムは、WSAStartup API呼び出しが成功した後でのみ、他の Windows Sockets 関数を呼び出すことが出来ます。

・WSADATA構造体の wVersion メンバが呼出し元の条件(想定)に合わない場合、プログラムは WSACleanup 関数を呼び出しWinSockDLLリソースを解放して、WinSockAPIの初期化失敗とする事が望ましいようです。

・最新のWinSockの仕様はバージョン2.2です。現在、以下のバージョンをサポートしています。
  1.0、1.1、2.0、2.1、2.2

・WINSOCK_VERSION は、最新バージョンを指定します。


【WSADATA構造体】

WSADATA構造体のメンバー
メンバー名説明
wVersion WORD 呼出し元が想定する WinSock API のバージョン
wHighVersion WORD DLL がサポートする最新の WinSock バージョン
szDescription char [*1] DLL に関する説明
szSystemStatus char [*2] DLL の状態や構成情報
iMaxSockets unsigned short 利用可能な最大ソケット数 *3
iMaxUdpDg unsigned short UDP データグラムの送受信最大サイズ *3
lpVendorInfo char FAR * ベンダー固有の情報へのポインタ

 *1:WSADESCRIPTION_LEN + 1、*2:WSASYS_STATUS_LEN + 1
 *3:WinSock1.1 下位互換のため


【HOSTENT構造体】

HOSTENT構造体のメンバー
メンバー名説明
h_name char FAR * ホストの正式名称
h_aliases char FAR * FAR * ホストの別名のポインタの配列
h_addrype short 要求されたアドレスの種類を表す定数
h_length short アドレスのバイト単位のサイズ *1
h_addr_list char FAR * FAR * ネットワークアドレス情報のポインタの配列

 *1:IPv4は4バイト、IPv6は16バイト


【IN_ADDR構造体】

IN_ADDR構造体のメンバー
メンバー名説明
s_addrunsigned longアドレスを表す数値 *1

 *1:ドット表記 xxx.yyy.zzz.xyz のIPアドレスを数値形式に変換した値


お試し環境
  WindowsXP 32bit Edition
  Visual C++ 2008


/*---- WinSockAPI ソケット使用 -------------- コマンドライン ---------------*/

D:\vc2008\dllchk>cl test.c ws2_32.lib

/*----------------------------------------------------------------------------*/


/*---------------------------------- お試し結果 ----------------------------*/

D:\vc2008\dllchk>test
最新バージョン = 2.2
DLLの説明 = WinSock 2.0
現在の状態 = Running

D:\vc2008\dllchk>test localhost
最新バージョン = 2.2
DLLの説明 = WinSock 2.0
現在の状態 = Running
正式名称 = biroku
IP = 127.0.0.1

D:\vc2008\dllchk>test 127.0.0.1
最新バージョン = 2.2
DLLの説明 = WinSock 2.0
現在の状態 = Running
正式名称 = localhost
IP = 127.0.0.1

/*----------------------------------------------------------------------------*/


/*---- test.c ------------------------ お試しソース ------------------------*/

#include <stdio.h>
#include <winsock2.h>

int main(int argc, char *argv[])
{
    WSADATA wsaData;
    LPHOSTENT host;
    IN_ADDR addr;
    int i, ret;

    // WinSock の初期化
    if((ret = WSAStartup(WINSOCK_VERSION, &wsaData)) != 0) {
        printf("WinSockの初期化に失敗しました:error = %d\n", ret);
        return(0);
    }
    printf("最新バージョン = %d.%d\nDLLの説明 = %s\n現在の状態 = %s\n", (BYTE)wsaData.wHighVersion, wsaData.wHighVersion >> 8, wsaData.szDescription, wsaData.szSystemStatus);

    if((BYTE)wsaData.wHighVersion < 2) {
        printf("WinSockの想定バージョンとサポートバージョンに相違があります。\n");
        return(0);
    }

    if(argc == 2) {
        addr.s_addr = inet_addr(argv[1]);
        if(addr.s_addr == INADDR_NONE) { // ホスト名なら
            host = gethostbyname(argv[1]);
        } else { // アドレスなら
            host = gethostbyaddr((const char *)&addr, sizeof(IN_ADDR), AF_INET);
        }
        if(host == NULL) {
            printf("ホスト名の取得に失敗しました:%s\n", argv[1]);
            return(0);
        }

        printf("正式名称 = %s\n", host->h_name);
        for(i = 0; host->h_aliases[i] != NULL; i++) {
            printf("別名 = %s\n", host->h_aliases[i]);
        }

        for(i = 0; host->h_addr_list[i] != NULL; i++) {
//          printf("IP = %d.%d.%d.%d\n", (BYTE)*(host->h_addr_list[i]), (BYTE)*((host->h_addr_list[i]) + 1), (BYTE)*((host->h_addr_list[i]) + 2), (BYTE)*((host->h_addr_list[i]) + 3));
            printf("IP = %s\n", inet_ntoa(*(IN_ADDR *)host->h_addr_list[i]));
        }
    }

    // WinSock のリソース解放
    WSACleanup();
    return(0);
}

/*----------------------------------------------------------------------------*/
/*============================================================================*/