サーバは簡単に言うと、次のような作法で作ることができます。
↓
接続要求受信用ソケットの設定
↓
接続待ち準備
↓
接続要求受付
↓
送受信
↓
切断
接続要求受信用ソケットの作成
ここではまず荒削りなソケットを作成します。
接続要求受信用ソケットの設定
このような背景を考慮して、次のようなアドレス設定ができるようになっています。
- 割り当てられたあるIPアドレスを指定した場合
- ループバックアドレスを指定した場合
- 0.0.0.0(INADDR_ANYというマクロで定義されている)を指定した場合
接続待ち準備
この準備では、最大いくつの要求を待たせるか、という設定を行います。
(この最大数を超えた要求が行われたとき、クライアント側は待たされず、即刻「接続拒否」を示すエラーを受け取ることとなります。)
接続要求受付
送受信
切断
そうしないとメモリなどの資源が使用されたままの状態になり、無駄が発生します。無駄が積み重なると有限である資源が枯渇することになります。
これらを実際にコードで書くと以下のようになります。
#include <stdio.h> #include <winsock2.h> int main(int argc, char** argv) { WSADATA wsaData; SOCKET listenSock; struct sockaddr_in addr; struct sockaddr_in client; int len; SOCKET commSock; char recvBuf[256]; int recvLen; printf("サーバプログラムスタート\n"); // Winsock2 DLL 初期化 WSAStartup(MAKEWORD(2,0), &wsaData); printf("接続要求受信用ソケットの作成\n"); listenSock = socket(AF_INET, SOCK_STREAM, 0); addr.sin_family = AF_INET; addr.sin_port = htons(12345); //任意のポート番号 addr.sin_addr.S_un.S_addr = INADDR_ANY; // 全てのアドレス printf("接続要求受信用ソケットの設定\n"); bind(listenSock, (struct sockaddr *)&addr, sizeof(addr)); printf("クライアントからの接続待ち準備\n"); listen(listenSock, 5); // クライアントからの接続要求受付 len = sizeof(client); printf("クライアントからの接続要求受付\n"); commSock = accept(listenSock, (struct sockaddr *)&client, &len); // 送信 printf("\"おはよう\"送信\n"); send(commSock, "おはよう", strlen("おはよう"), 0); recvLen = recv(commSock, recvBuf, sizeof(recvBuf), 0); recvBuf[recvLen] = '\0'; printf("\"%s\"受信\n", recvBuf); printf("切断\n"); closesocket(commSock); closesocket(listenSock); // Winsock2 DLL 終了 WSACleanup(); return 0; }
上記プログラムは、
- 接続要求受信用ソケットを作成(socket())し、アドレスやポート番号などを設定(bind())します。
- クライアントからの接続待ち準備(listen())を行い、クライアントからの接続受け付ける(accept())とそのクライアントに対して「おはよう」というメッセージを送信(send())します。
- その後、クライアントからのなんらかのメッセージが来るのを待ち、受信(recv())するとそのメッセージを表示(printf())します。
- 表示後、通信を切断(closesocket())し、プログラムは終了します。
WSAStartupとWSACleanupはWinsock2を使用するために必要です。Winsock2利用区間で呼び出すようにしてください。
さらにWinsock2を利用するためには「Winsock2を使いますよ(ライブラリをリンクしますよ)」という設定をしておく必要があります。
- ソリューションエクスプローラーで「server」を選択してください。この状態で、「プロジェクト」>「プロパティ」を選択してください。
- プロパティページが表示されます。「構成プロパティ」>「リンカー」>「入力」を選択してください。
- 右のフレーム内、「追加の依存ファイル」に対する値の末尾に「;ws2_32.lib」を追加し、「OK」をクリックしてください。
これでWinsock2を利用できるようになりました。
さらにMicrosoft Visual C++ Expressの高度な機能を利用するために、「ツール」>「設定」>「上級者用の設定」にします。
では、プログラムをビルドしてみましょう。
- 「ビルド」>「server ビルド」を選択してください。
- ビルドが正常に動作した場合は、
「1 正常終了」
となります。もし失敗したならば、もう一度各種設定、コードを確認してください。
では、プログラムを実行してみましょう。
- 「デバッグ」>「デバッグなしで開始」を選択してください。(「デバッグなしで開始」がないっ!という方は、先に説明した「上級者用の設定」をしてください。「デバッグなしで開始」でプログラムを動作させるのはプログラム終了時にコンソールを閉じないためです。)
- 下図のような結果になれば意図通り動作しています。
accept()処理でクライアントからの接続を待っている状態になっています。
さて、accept()処理が戻る、つまり、クライアントからの接続を行わなければ、処理を進めることができません。クライアントを作る必要があるのですが、ここでちょっと近道をして既存のツールを利用してクライアントを肩代わりさせる方法を紹介します。(クライアントも後で作成します。)
そのツールは「SocketDebugger」というものです。>>SocketDebuggerっ
て何?