Skip to main content.

Wednesday, August 16, 2006

WinSockでHTTPサーバ(その1)

WinSockを利用した簡単なサーバアプリケーションのサンプルです。WinSockは、Windowsでソケットプログラミングを行なうためのAPIです。ソケットプログラミングはネットワークプログラミングの代表的なもので、インターネット、書籍等で情報が得られます。概要、詳細等はそちらを参照して下さい。

ここでは、このWinSockを利用して、HTTPの機能の一部を提供するWebサーバ的なプログラムを作成してみました。出来ることは、ブラウザ(クライアント)からURLを指定してGETメソッドでファイルを取得することです。実装は、VC++(Ver6.0)のコンソールアプリケーションです。使い方は、まずc:\WebPagesにHTMLファイル、画像ファイル等のコンテンツを用意します。そして、単純に起動すると、コンソールアプリケーションが起動されます。ブラウザから普通に、http://サーバ名(IPアドレス):ポート番号/ファイル名でURLを指定すると、c:\WebPagesにファイルがあれば、ヘッダ(ステータスとContentLengthのみ)とそのファイルをブラウザに返します。単純なHTMLのページと画像ぐらいは表示出来ます。サーバを終了させる場合は、強制終了か、http://サーバ名(IPアドレス):ポート番号/endを指定してください。

処理の流れと使用しているAPIは以下になります。典型的なソケットプログラミングでのサーバアプリケーションの流れだと思います。

・WinSock初期化 WSAStartup()
・ソケット生成 socket()
・ソケットにIP、PORTを登録 bind()
・ソケット接続準備 listen()

以下、終了まで繰り返し
・accept() ソケット接続待機 ←ここでクライアント(ブラウザ)からの接続待ち
・接続単位にスレッドを生成
・スレッドでURLの取得をして、recv()、ヘッダ(ステータスとContentLength)とファイルを送信 send()
・/endの場合は、終了処理 shutdown()、closesocket()

・終了時、WinSock終了 WSACleanup()

以下は、ソースの一部です。ソース全体は、お手数ですが、プロジェクト一式をダウンロードしてご覧下さい。

VC++ 6.0のプロジェクトファイルとサンプルページのディレクトリを以下に置きました。
プロジェクト一式

動作確認はしましたが、動作は保証できません。このプログラムを利用しての不具合、不利益には一切の責任を負いかねます。ご了承ください。

// WinSock関数
int funcWinSock()
{
SOCKET cl_sock; //clientソケット
SOCKADDR_IN skaddr,cl_addr;

int ret;
int port;
int alen;

// ソケットの生成
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET){
printf("ソケット生成エラー\n");
return 0;
}
printf("ソケット生成\n");

port = PORTNUM;
memset(&skaddr, 0, sizeof(skaddr));
skaddr.sin_family = AF_INET;
skaddr.sin_port = htons(port);
skaddr.sin_addr.s_addr = INADDR_ANY;

// ソケットにIP、ポートを割り当て
ret = bind(sock, (struct sockaddr *)&skaddr, sizeof(skaddr));
if (ret == SOCKET_ERROR){
printf("bind エラー\n");
return 0;
}

// 接続を受け入れるキューを最大に作成
ret = listen(sock, SOMAXCONN);
if (ret == SOCKET_ERROR){
printf("listen エラー\n");
return 0;
}
printf("接続待ち\n");

// 接続を待つ
while (1){
alen = sizeof(struct sockaddr);
cl_sock = accept(sock, (struct sockaddr *)&cl_addr, &alen);
if(cl_sock == INVALID_SOCKET){
printf("acceptエラー\n");
if(sock != 0){
closesocket(sock);
}
break;
}

/* スレッドで処理 */
if (_beginthread((void (*)(void *)) sendThread, 0, (void *)cl_sock) == (unsigned)-1){
printf("スレッドエラー GetLastError = %d\n", GetLastError());
}
}

return 0;
}

参考サイト
Winsock Programmer's FAQ の日本語訳


Windowsプログラミング関連記事