となります。
- WSAStartup関数でWinSockの初期化を行います。
(プログラムの開始時のみ)
- socket関数でソケットの作成を行います。
- bind関数でローカルのポート番号を指定する。
- サーバのIPアドレスを取得します。inet_addr関数およびgethostbyname関数でサーバのIPアドレスの取得を行います。
(送信と受信で使用します)
- ソケットに対して、sendto関数でサーバを指定して送信、recvfrom関数でサーバを指定して受信を行います。
- closesocket関数でソケットを破棄します。
- WSACleanup関数でWinSockのリソースを解放する。
(プログラムの終了時のみ)
wsock32.libをリンクする必要があります。
winsock.hをインクルード
■ : ソケットとなっています。
■ : コメント
太字 : メインのAPI
WORD wVersionRequested; int nErrorStatus; WSADATA wsaData; /* WinSockの初期化を行う */ wVersionRequested = MAKEWORD(1, 1); /* バージョン 1.1 を要求する */ nErrorStatus = WSAStartup(wVersionRequested, &wsaData); if (atexit((void (*)(void))(WSACleanup))) { /* 終了時にWinSockのリソースを解放するようにしておく */ fprintf(stderr,"atexit(WSACleanup)失敗\n"); exit(-1); } if ( nErrorStatus != 0 ) { fprintf(stderr,"WinSockの初期化失敗\n"); exit(-1); }
WSAStartup関数の第一引数は、要求するWinSockのバージョンを入れます。
もし、バージョン 2.0 を要求する場合は、
MAKEWORD(2, 0)
と指定します。
atexit((void (*)(void))(WSACleanup))は、終了時にWSACleanup関数を実行するようにしています。
int soc; /* ソケット(Soket Descriptor) */ /* socにソケットを作成します */ soc = socket(PF_INET, SOCK_DGRAM, 0); if(soc == INVALID_SOCKET){ fprintf(stderr,"ソケット作成失敗\n"); }
socket関数の第1引数には、インターネットを表すPF_INETを指定して、第2引数にはUDPを表すSOCK_DGRAMを指定しています。
第3引数は、プロトコルを指定します。
struct sockaddr_in sockname; /* ソケットのアドレス */ /* ソケットのアドレスの構造体にサーバのIPアドレスとポート番号を設定します */ sockname.sin_family = AF_INET; /* インターネットの場合 */ sockname.sin_addr.s_addr = INADDR_ANY; /* 自分のIPアドレスを使うようにする */ sockname.sin_port = htons((unsigned short)local_port); /* ローカルのポート番号 */ memset(sockname.sin_zero,(int)0,sizeof(sockname.sin_zero)); if(bind(soc,(struct sockaddr *)&sockname,sizeof(sockname)) == SOCKET_ERROR){ fprintf(stderr,"受信ポート番号の指定に失敗\n"); }
サーバが送信したデータを受信するローカルのポート番号をbind関数で指定しています。
bind関数の第1引数は、socket関数で作成されたソケットです。
第2引数は、ソケットのアドレスの構造体へのポインタで、第3引数はその構造体のサイズです。
ポート番号の指定のところで、htons((unsigned short)port)とありますが、これはホストのバイト並び(16bit)をネットワークのバイト並び(16bit)に変換しているのです。
32bitのホストのバイト並びをネットワークのバイト並びに変換するには、htonl関数を使います。
逆にネットワークのバイト並びをホストのバイト並びに変換するには、ntohs関数とntohl関数があります。
unsigned long serveraddr; /* サーバのIPアドレス */ struct hostent *serverhostent; /* サーバのホスト情報を指すポインタ */ /* svNameにドットで区切った10進数のIPアドレスが入っている場合、serveraddrに32bit整数のIPアドレスが返ります */ serveraddr = inet_addr((char*)svName); if (serveraddr == -1) { /* サーバ名(svName)からサーバのホスト情報を取得します */ serverhostent = gethostbyname(svName); if (serverhostent == NULL) { fprintf(stderr,"ホストアドレス取得失敗\n"); }else{ /* サーバのホスト情報からIPアドレスをserveraddrにコピーします */ serveraddr = *((unsigned long *)((serverhostent->h_addr_list)[0])); } }
svNameにドットで区切った10進数のIPアドレスが入っている場合は、inet_addr関数で32bitの整数値に変換されます。
例)
210.146.62.2 -(inet_addr)→ 23E92D2
svNameにサーバのホスト名が入っている場合は、gethostbyname関数でサーバのホスト情報を取得します。
そして、サーバのホスト情報の中からIPアドレスを取り出します。
例)
www.kinet.or.jp -(gethostbyname)→ サーバのホスト情報(この中のIPアドレスを取り出します)
struct sockaddr_in serversockaddr; /* サーバのアドレス */ /* サーバのアドレスの構造体にサーバのIPアドレスとポート番号を設定します */ serversockaddr.sin_family = AF_INET; /* インターネットの場合 */ serversockaddr.sin_addr.s_addr = serveraddr; /* サーバのIPアドレス */ serversockaddr.sin_port = htons((unsigned short)port); /* ポート番号 */ memset(serversockaddr.sin_zero,(int)0,sizeof(serversockaddr.sin_zero)); /* サーバを指定して文字列(buf)を送信します */ /* 送信した文字列は指定したサーバに届きます */ if(sendto(soc, buf, lstrlen(buf), 0,(struct sockaddr *)&serversockaddr,sizeof(serversockaddr)) == SOCKET_ERROR){ fprintf(stderr,"サーバへの送信失敗\n"); }
sendto関数の第1引数は、socket関数で作成されたソケットです。
第2引数は送信する文字列のバッファで、第3引数は文字列の長さです。
第5引数は、送信先サーバのアドレスの構造体へのポインタで、第6引数はその構造体のサイズです。
#define RECVSIZE 256 /* 受信サイズ */ char buf[256]; /* 受信するバッファ */ int buf_len; /* 受信したバイト数 */ struct sockaddr_in serversockaddr; /* サーバのアドレス */ int sockaddr_size; /* サーバのアドレスのサイズ */ /* サーバのアドレスの構造体にサーバのIPアドレスとポート番号を設定します */ serversockaddr.sin_family = AF_INET; /* インターネットの場合 */ serversockaddr.sin_addr.s_addr = serveraddr; /* サーバのIPアドレス */ serversockaddr.sin_port = htons((unsigned short)port); /* ポート番号 */ memset(serversockaddr.sin_zero,(int)0,sizeof(serversockaddr.sin_zero)); /* サーバを指定して文字列を受信します */ /* 受信した文字列は buf に入ります */ sockaddr_size = sizeof(serversockaddr); buf_len = recvfrom(soc, buf, RECVSIZE - 1, 0,(struct sockaddr *)&serversockaddr,&sockaddr_size); if (buf_len == SOCKET_ERROR ){ fprintf(stderr,"サーバからの受信失敗\n"); } buf[buf_len] = '\0'; /* 受信したバッファの後ろにヌル文字を付加する */
recvfrom関数の第1引数は、socket関数で作成されたソケットです。
第2引数は受信するバッファで、第3引数は受信バッファのサイズです。
第5引数は、受信するデータを送信したサーバのアドレスの構造体へのポインタで、第6引数はその構造体のサイズの入った変数へのポインタです。
/* ソケットを破棄する */ closesocket(soc);
closesocket関数の第1引数は、socket関数で作成されたソケットです。
/* WinSockのリソースを解放します */ WSACleanup();
WinSockのリソースを解放する関数ですが、プログラムの初めにatexit()を使って終了時に呼び出されるようにしておけばいいと思います。
WinSockのAPIを使用してエラーになった場合、WSAGetLastError関数でエラーコードを取得することができます。