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構造体】
メンバー名 | 型 | 説明 |
---|---|---|
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構造体】
メンバー名 | 型 | 説明 |
---|---|---|
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構造体】
メンバー名 | 型 | 説明 |
---|---|---|
s_addr | unsigned 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);
}
/*----------------------------------------------------------------------------*/
/*============================================================================*/