| |||||||||||||||||||||||||||||||||||||||||
サイト内検索
カスタム検索
|
はじめての WinSock 2 プログラムの説明それでは今回は、前回ビルドした はじめての WinSock2 プログラム の内容を説明します。 まだ試していない人はそちらもチラ見しておいてください。 では、コードを上からいきます。 ヘッダーファイル ~ WinSock2 用は winsock2.h と ws2tcpip.hヘッダーファイルは次の3つを取り込んでいます。 #include <stdio.h> #include <winsock2.h> #include <ws2tcpip.h> WinSock 2 を利用するときの基本的なヘッダファイルは winsock2.h です。 ws2tcpip.h には WinSock2 PSA (WinSock 2 Protocol-Specific Annex) で新しく定義されたデータ構造や関数が定義されています。 stdio.h は説明するまでもありませんね。 printf 等を使うために取り込んでいます。 WinSock の初期化最初にやらないといけないことは、WinSock ライブラリの初期化です。初期化は WSAStartup 関数を使います。 int main(int argc, char* argv[]) { INT rc; WSADATA wsaData; addrinfo hints, *pAddrInfo = NULL; ZeroMemory(&hints, sizeof(addrinfo)); SOCKADDR_IN *pSockAddr_in; ... // WinSock の初期化 rc = WSAStartup(MAKEWORD(2, 2), &wsaData); if( rc ) { printf("WSAStartup Failed.\n"); return 1; } WSAStartup を呼び出す時に、第一引数にこれから使う WinSock のバージョンを指定します。 通常ためらわず最新バージョンの 2.2 を使うはずですから、ここでは 2.2 を指定しています。 ちなみに winsock2.h でも WINSOCK_VERSION という便利マクロが定義されてます。 #ifndef WINSOCK_VERSION #define WINSOCK_VERSION MAKEWORD(2,2) #endif 第二引数の WSADATA 構造体は次のような形をしています。
typedef struct WSAData {
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR *lpVendorInfo;
} WSADATA, *LPWSADATA;
一見ややこしいですがバージョン 2 以降ではあまり役に立つ情報を返してこないので、 気にしなくて構いません。 WSAStartup の確認ツール ~ StartupTest「いや、気になる!」 という方は、私が以前使ったツールがあるので、それで試してみてください。
このツールは WSAStartup の第一引数のバージョンを変えて呼び出すと、 WSADATA にどのような値が返ってくるか見るだけのツールです。(私も暇ですね。こんなもの作って...(苦笑)) では次に行きましょう。 アドレス情報の取得さていよいよ getaddrinfo 関数を使って、"www.microsoft.com" 等の名前を IP アドレスに解決します。 addrinfo hints, *pAddrInfo = NULL; ZeroMemory(&hints, sizeof(addrinfo)); SOCKADDR_IN *pSockAddr_in; ... // アドレス情報の取得 hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; rc= getaddrinfo( argv[1], "http", &hints, &pAddrInfo); if( rc ) { printf("getaddrinfo Failed. rc = %d \n", rc); return 1; } getaddrinfo は次の形をしています。 int WSAAPI getaddrinfo( __in const char *nodename, __in const char *servname, __in const struct addrinfo *hints, __out struct addrinfo **res ); 第 1 引数に名前を渡し、第 2 引数にサービス名 (プロトコル名) またはポート番号を文字列で渡し、 第 3 引数に解決のヒントを渡して呼び出すと、第 4 引数にその結果が返ってくる、ということになります。 ぶっちゃけ通常、サービス名及びヒントの部分は両方 NULL でも問題ありません。ちゃんと名前解決されて返ってきます。 ここでわざわざヒントとして設定してみたパラメータの意味を詳しく知りたい方は MSDN をご覧ください。 またサービス名まで渡してあげると、結果のなかにポート番号まで入ってきて便利です。 結果の表示結果は getaddrinfo の第 4 引数に返ってきます。型は addrinfo へのポインタです。 addrinfo は次のように定義されています。次のノードへのポインタを *ai_addr で保持する、単方向リストです。つまり言い換えると、第 4 引数に返ってくるのは addrinfo リストのリストヘッドが返ってきています。
typedef struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
char *ai_canonname;
struct sockaddr *ai_addr;
struct addrinfo *ai_next;
} ADDRINFOA, *PADDRINFOA;
リストですから、ループで結果を表示しています。次のノードのポインタが NULL になったところでループを抜けます。 while (1) { printf ("------------------------------\n"); printf ("Canon Name: %s\n", pAddrInfo->ai_canonname ? pAddrInfo->ai_canonname : ""); pSockAddr_in = (SOCKADDR_IN*) pAddrInfo->ai_addr; printf ("Port: %d\n", ntohs(pSockAddr_in->sin_port)); printf ("Addr: %s\n", inet_ntoa(pSockAddr_in->sin_addr)); if( !pAddrInfo->ai_next ) { break; } pAddrInfo = pAddrInfo->ai_next; } freeaddrinfo(pAddrInfo); アドレス情報は ai_addr に返ってきます。これは IPv4 の環境では SOCKADDR_IN* にキャスト可能です。 SOCKADDR_IN が取れれば、アドレス情報はその中のメンバーである sin_addr を inet_ntoa に渡すことによって、IP アドレスの文字列表現を取得することが出来ます。 SOCKADDR_IN については別ページ WinSock での IP アドレスとポートの扱い方 で説明していますのでそちらも見てください。 結果が不要になったら freeaddrinfo に渡してメモリを解放します。 WinSock のクリーンアップWinSock2 を使ったら最後に WSACleanup を呼び出してクリーンアップします。 // WinSock のクリーンアップ WSACleanup(); return 0; } 以上、はじめての WinSock2 の説明でした。慣れないデータタイプが出てきて、 最初は 「なんだこれ?」 と思うかもしれませんが、頑張ってみてください! |
||||||||||||||||||||||||||||||||||||||||
|
© 2008-2010 小山圭介 All Rights Reserved.
|
|||||||||||||||||||||||||||||||||||||||||