簡単なWebサーバを実装してみます。
簡易的なHTTPの機能しかないので、
webサーバというよりは、
HTTPサーバと呼ぶべきでしょうか。
今回行うことは・・・
HTTPで通信してきた
クライアントに対して、
HTTP 404 Not Foundを
無条件でリプライします。
まずソースはこちらです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
#include<stdlib.h> #include<stdio.h> #include<string.h> #include<fcntl.h> #include<sys/socket.h> #include<arpa/inet.h> #include<unistd.h> #define PORT 80 void startserver(int *serversoc); void handle_webpage(int clientsoc, struct sockaddr_in *clientaddr); void send_data(int clientsoc, char *buf); int main(void){ int serversoc, clientsoc; struct sockaddr_in clientaddr; socklen_t len; startserver(&serversoc); //serverソケット作成 printf("[+]Start www.server...\n"); //クライアントからの接続要求きたらつなげる while(1){ len = (socklen_t)sizeof(clientaddr); if((clientsoc=accept(serversoc, (struct sockaddr*)&clientaddr, &len))<0){ fprintf(stderr, "accept()\n"); exit(1); } handle_webpage(clientsoc, &clientaddr); //404NotFoundを返す処理 } return 0; } //サーバ側のソケットを作成する一般的な手順と同じ。 void startserver(int *serversoc){ int opt=1; //setsockopt関数に必要 struct sockaddr_in serveraddr; if((*serversoc=socket(PF_INET, SOCK_STREAM, 0))<0){ fprintf(stderr, "socket()\n"); exit(1); } if((setsockopt(*serversoc, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))==-1){ fprintf(stderr, "setsockopt()\n"); close(*serversoc); exit(1); } memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = PF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons(PORT); if(bind(*serversoc, (struct sockaddr *)&serveraddr, sizeof(serveraddr))<0){ fprintf(stderr, "bind()\n"); close(*serversoc); exit(1); } if(listen(*serversoc, 10)<0){ fprintf(stderr, "listen()\n"); close(*serversoc); exit(1); } } //404NotFoundを返す処理 void handle_webpage(int clientsoc, struct sockaddr_in *clientaddr){ char *ptr; char addr[INET_ADDRSTRLEN];//IPアドレス格納用 //IPアドレスを数値からx.x.x.xの形に変更して表示 printf("[+]Client: %s / %d\n", inet_ntop(AF_INET, &clientaddr->sin_addr, addr, sizeof(addr)), ntohs(clientaddr->sin_port)); send_data(clientsoc, "HTTP/1.1 404 NOT FOUND\r\n"); //HTTPレスポンスステータスラインを送信 send_data(clientsoc, "Server: www server\n\n\r\n"); //これもないとエラーになる send_data(clientsoc, "<html><head><title>404 Not Found</title></head>"); //表示するwebページを送信 send_data(clientsoc, "<body><h1>URL not found</h1></body></html>\r\n"); //表示するwebページを送信パート2 close(clientsoc); //必ず閉じること。TCPコネクションの関係上、webページが表示されない。 } //送信するだけ。特に変わった処理はない。 void send_data(int clientsoc, char *buf){ if(send(clientsoc, buf, strlen(buf), 0)<0){ fprintf(stderr, "send()\n"); exit(1); } } |
最初に接続を待つポートに、
80番ポート(HTTP)を定義しています。
(main分)
大まかな処理の流れは、
- ソケット作成して、接続を待つ
- クライアントと接続したらHTTP処理を行う
これだけです。
ソケット作成&待機は、
startserver関数で定義して、
HTTP処理は、
handle_webpage関数で定義しています。
なおhandle_webpage関数から、
送信のみを行う関数として、
send_data関数に派生しています。
send_data関数はコードを
見やすくするためだけに
関数化してあるあります。
handle_webpage関数内で
送信しても問題ありません。
handle_webpage関数内で、
HTTPリクエストに対して、
無条件で404を返す処理をしています。
"HTTP1.1 404 Not Found"を
送信してからwebページを送ります。
webページは簡易的なものなので、
ファイル化せず、そのまま送ります。
もちろん、ファイル化して
それをreadして送信するのも可能です。
またクライアン側の
IPアドレスとポート番号も表示しています。
サーバ側の実行画面です。

作成したwebサーバに
クライアントがアクセスした時、
実際に表示される画面です。

これでWebサーバの礎は完成です。
これを拡張してみるのも面白いです。
webブラウザからではなく、
cygwinを用いてコマンドで
接続してみてみます。

以上です。
最後まで読んでいただきありがとうございました。