[ C++で開発 ]
WindowsOS上でWinSock APIを使用したIPv6ソケットプログラミングの方法を調べて記述します。
まずWinSockを使った簡単なソケットプログラミングのサンプルを見てみましょう。
TCP(コネクション指向)のソケット通信を行うサンプルです。エラー処理はばっさり省略しAPI使用に関わる部分だけを記述しています。
#include <winsock2.h> #include <ws2tcpip.h> // WinSockの初期化 WORD version = MAKEWORD(2, 2); WSADATA wsa; WSAStartup(version, &wsa); // ホスト情報の作成 ADDRINFO hints; memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; LPADDRINFO res; int ret = getaddrinfo("foo.bar", NULL, &hints, &res); // ソケットの作成 SOCKET sock = socket(res->ai_family, res_ai_socktype, res->ai_protocol); // 接続 connect(sock, res->ai_addr, res->ai_addrlen); // 送信 const char *send_buffer = "Hello, WinSock World!"; send(sock, send_buffer, sizeof(send_buffer), 0); // 受信 char recv_buffer[1024]; int size = recv(sock, recv_buffer, sizeof(recv_buffer)-1, 0); // 切断 closesocket(sock); // WinSockの終了手続き WSACleanup(); |
WinSockバージョンとWinSock情報構造体(WSADATA)へのポインタを渡してWSAStartupを呼び出します。WSADATAはWinSock詳細データが格納されて返ります。WinSockバージョンは、メジャーバージョン番号とマイナーバージョン番号からなり、最新バージョンは2.2)、TCP/IP以外のトランスポート対応や性能向上などが加わっています。
ソケットではホスト情報をIPアドレスやホスト名で扱います。文字列で表現するIPアドレスおよびホスト名は、getaddrinfo関数を使用して文字列からアドレス情報へ変換します。アドレス情報は、ADDRINFO型ですが、これはPOSIX 1003.1g(またはRFC 2553)で記載されるstruct addrinfoのtypedefとなっています。(なぜかWindows系のAPIでは大文字で表現する型名へのtypedefが多用される)
WinSock APIを使用する場合、WinSockライブラリとリンクする必要があります。プロジェクトのリンク設定に、ws2_32.libを追加します。
使用関数/型 | ヘッダファイル | 用途 |
WORD | (winsock.h) | WSAStartupの第1引数に使用 |
MAKEWORD() | ||
WSADATA | WSAStartupの第2引数に使用 | |
WSAStartup() | WinSockライブラリ初期化 | |
WSACleanup() | WinSockライブラリ解放 | |
LPHOSTENT | struct hostent* のtypedef定義 | |
gethostbyname() | ホスト名からホスト情報へ変換 | |
SOCKET | u_intのtypedef定義 | |
AF_INET | ||
SOCK_STREAM | ||
INVALID_SOCKET | -1のデファイン | |
SOCKADDR_IN | struct sockaddr_inのtypedef定義 | |
htons() | ||
LPIN_ADDR | struct in_addr*のtypedef定義 | |
connect() | ||
LPSOCKADDR | struct sockaddr*のtypedef定義 | |
SOCKET_ERROR | -1のデファイン | |
closesocket() |
時折、以下のようなコンパイルエラーに直面します。
ws2def.h(91) : warning C4005: 'AF_IPX' : マクロが再定義されました。 winsock.h(460) : 'AF_IPX' の前の定義を確認してください ws2def.h(127) : warning C4005: 'AF_MAX' : マクロが再定義されました。 winsock.h(479) : 'AF_MAX' の前の定義を確認してください ws2def.h(163) : warning C4005: 'SO_DONTLINGER' : マクロが再定義されました。 winsock.h(402) : 'SO_DONTLINGER' の前の定義を確認してください ws2def.h(206) : error C2011: 'sockaddr' : 'struct' 型の再定義 winsock.h(485) : 'sockaddr' の宣言を確認してください。 ws2def.h(384) : error C2143: 構文エラー : '}' が '定数' の前にありません。 ws2def.h(384) : error C2143: 構文エラー : ';' が '定数' の前にありません。 ws2def.h(384) : error C2059: 構文エラー : '定数' ws2def.h(437) : error C2143: 構文エラー : ';' が '}' の前にありません。 ws2def.h(437) : error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません ws2def.h(437) : error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
主な原因は、<WinSock2.h>より先に<windows.h>がインクルードされたことです。
Windowsの制約として、windows.hよりも先にwinsock2.hをインクルードすることが必要です。
これは、Windowsには古いWinsockと新しいWinsockがあり、windows.hは何も制御しないと古いWinsockを読み込みます。
#include <WinSock2.h> #include <windows.h>