何も高度なフレームワークを使用せずに、C++ 標準ライブラリといくつかのシステムコールを使用して、シンプルな HTTP サーバーを実装できます。以下は、C++ 標準ライブラリの <iostream>
や <sys/socket.h>
などのヘッダーファイルを使用して、シンプルな HTTP サーバーを作成し、リクエストを受け取り、シンプルなレスポンスを返す方法を示す基本的な例です。この HTTP サーバーは一度のネットワークリクエストのみを処理しますが、リクエストを継続的に処理したい場合は、後でループを追加してリクエストを常に処理できるようにすることができます。
例:シンプルな HTTP サーバー#
この例では、原始的なソケットプログラミングを使用して、ポートをリッスンし、incoming 接続を処理するシンプルな HTTP サーバーを作成します。
#include <iostream>
#include <string>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
// ソケットを作成
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
std::cerr << "ソケットの作成中にエラーが発生しました" << std::endl;
return 1;
}
// ソケットオプションを設定し、アドレスの再利用を許可
int opt = 1;
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
std::cerr << "ソケットオプションの設定中にエラーが発生しました" << std::endl;
return 1;
}
// サーバーアドレス構造体
struct sockaddr_in address;
int addrlen = sizeof(address);
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
// ソケットをアドレスにバインド
if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
std::cerr << "ソケットのバインド中にエラーが発生しました" << std::endl;
return 1;
}
// 接続をリッスン
if (listen(server_fd, 3) < 0) {
std::cerr << "ソケットのリッスン中にエラーが発生しました" << std::endl;
return 1;
}
std::cout << "ポート8080でサーバーがリッスンしています" << std::endl;
// 接続を受け入れる
int new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
if (new_socket < 0) {
std::cerr << "接続の受け入れ中にエラーが発生しました" << std::endl;
return 1;
}
// リクエストを受信
char buffer[1024] = {0};
read(new_socket, buffer, 1024);
std::cout << "リクエスト: " << buffer << std::endl;
// レスポンスを送信
const std::string response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<html><body><h1>こんにちは、世界!</h1></body></html>";
send(new_socket, response.c_str(), response.size(), 0);
// ソケットを閉じる
close(new_socket);
close(server_fd);
return 0;
}
コードの説明#
-
ソケットの作成:
socket
関数を使用して TCP ソケットを作成します。
-
ソケットオプションの設定:
setsockopt
関数を使用してSO_REUSEADDR
とSO_REUSEPORT
オプションを設定し、アドレスとポートの再利用を許可します。
-
サーバーアドレス構造体:
sockaddr_in
構造体を使用してサーバーのアドレス情報を格納します。INADDR_ANY
は、サーバーが任意の IP アドレスの接続を受け入れることを示します。
-
ソケットのバインド:
bind
関数を使用してソケットを指定されたアドレスとポートにバインドします。
-
接続のリッスン:
listen
関数を使用して接続のリッスンを開始します。パラメータ3
は最大接続キューの長さを示します。
-
接続の受け入れ:
accept
関数を使用して incoming 接続を受け入れます。
-
リクエストの受信:
read
関数を使用して接続からリクエストデータを読み取り、標準出力に印刷します。
-
レスポンスの送信:
- シンプルな HTTP レスポンス文字列を構築し、
send
関数を使用してレスポンスを送信します。
- シンプルな HTTP レスポンス文字列を構築し、
-
ソケットの閉鎖:
close
関数を使用して接続とリッスンソケットを閉じます。
コンパイルと実行#
上記のコードを http_server.cpp
として保存し、次のように g++ でコンパイルして実行します:
g++ -o http_server http_server.cpp
./http_server
テスト#
ブラウザを開くか、curl
を使用してサーバーをテストします:
curl http://localhost:8080
"こんにちは、世界!" というレスポンスが返ってくるはずです。
注意事項#
- この例はデモ目的のみであり、実際のアプリケーションでは、複数の接続を処理するためのマルチスレッドまたは非同期処理、HTTP リクエストの解析、異なる HTTP メソッドやパスの処理など、より多くのエッジケースを処理する必要があります。
- この例では、HTTP リクエストのヘッダーとボディの分離を処理していないため、実際のアプリケーションではより複雑な解析ロジックが必要になる場合があります。