Internet Programming
TCPクライアントの作成手順(同期型)
[1997/11/28]
■TCPクライアント作成の流れ
TCPクライアントの簡単な流れは、
1.ソケットの作成を行う。
↓
2.サーバに接続する。
↓
3.サーバと送受信を行う。
↓
4.ソケットを破棄する。
の4段階から成り立ちます。
実際にプログラムで使うWinSockのAPI(Socket Interface)を使用してもう少し詳しくあらわすと、
- WSAStartup関数でWinSockの初期化を行います。
(プログラムの開始時のみ)
- socket関数でソケットの作成を行います。
- サーバのIPアドレスを取得します。inet_addr関数およびgethostbyname関数でサーバのIPアドレスの取得を行います。
- 作成されたソケットを使用して、サーバのIPアドレスとポート番号を指定してconnect関数でサーバに接続(コネクト)します。
- ソケットに対して、send関数で接続しているサーバに送信、recv関数でサーバから受信を行います。
- shutdown関数で送受信を無効にして、closesocket関数でソケットを破棄します。
- WSACleanup関数でWinSockのリソースを解放する。
(プログラムの終了時のみ)
となります。
■APIの使用方法
WinSockのAPIを使用した例を示します。
WinSockを使用する際は、
wsock32.libをリンク
winsock.hをインクルード
する必要があります。
ソース中は、
■ : ソケット
■ : コメント
太字 : メインのAPI
となっています。
●WinSockの初期化の例
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_STREAM, 0);
if(soc == INVALID_SOCKET){
fprintf(stderr,"ソケット作成失敗\n");
}
socket関数の第1引数には、インターネットを表すPF_INETを指定して、第2引数にはTCPを表すSOCK_STREAMを指定しています。
第3引数は、プロトコルを指定します。
●サーバのIPアドレス取得の例
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));
/* 指定のソケットでサーバへコネクトします */
if(connect(soc,(struct sockaddr *)&serversockaddr,sizeof(serversockaddr)) == SOCKET_ERROR){
fprintf(stderr,"サーバへの接続失敗\n");
}
サーバのアドレスの構造体にサーバのIPアドレスとポート番号を設定して、connect関数で接続を行っています。
connect関数の第1引数は、socket関数で作成されたソケットです。
第2引数は、サーバのアドレスの構造体へのポインタで、第3引数はその構造体のサイズです。
ポート番号の指定のところで、htons((unsigned short)port)とありますが、これはホストのバイト並び(16bit)をネットワークのバイト並び(16bit)に変換しているのです。
32bitのホストのバイト並びをネットワークのバイト並びに変換するには、htonl関数を使います。
逆にネットワークのバイト並びをホストのバイト並びに変換するには、ntohs関数とntohl関数があります。
●サーバに文字列を送信する例
/* 指定のソケットに文字列(buf)を送信します */
/* 送信した文字列はサーバに届きます */
if(send(soc, buf, lstrlen(buf), 0) == SOCKET_ERROR){
fprintf(stderr,"サーバへの送信失敗\n");
}
send関数の第1引数は、socket関数で作成されたソケットです。
第2引数は送信する文字列のバッファで、第3引数は文字列の長さです。
●サーバから文字列を受信する例
#define RECVSIZE 256 /* 受信サイズ */
char buf[RECVSIZE]; /* 受信するバッファ */
int buf_len; /* 受信したバイト数 */
/* ソケットから文字列を受信します */
/* 受信した文字列は buf に入ります */
/* 受信する文字列はサーバが送信したものです */
buf_len = recv(soc, buf, RECVSIZE - 1, 0);
if (buf_len == SOCKET_ERROR ){
fprintf(stderr,"サーバからの受信失敗\n");
}else{
buf[buf_len] = '\0'; /* 受信したバッファの後ろにヌル文字を付加する */
}
recv関数の第1引数は、socket関数で作成されたソケットです。
第2引数は受信するバッファで、第3引数は受信バッファのサイズです。
文字列を受信する場合は、受信した文字列の最後にヌル文字は付加されていないので、recv関数の戻り値である受信サイズを使ってヌル文字を付加します。
●ソケットを破棄する例
/* 送受信を無効にする */
shutdown(soc, 2);
/* ソケットを破棄する */
closesocket(soc);
shutdown関数の第1引数は、socket関数で作成されたソケットです。
第2引数は、送信と受信の両方を無効にしています。
closesocket関数の第1引数は、socket関数で作成されたソケットです。
●WinSockのリソースを解放する例
/* WinSockのリソースを解放します */
WSACleanup();
WinSockのリソースを解放する関数ですが、プログラムの初めにatexit()を使って終了時に呼び出されるようにしておけばいいと思います。
●エラーコードを取得する場合
WinSockのAPIを使用してエラーになった場合、WSAGetLastError関数でエラーコードを取得することができます。

メールアドレス
<nakka@nakka.com>

Internet Programming