rkey

rkey

cppでHTTPサーバーを作成する

何も高度なフレームワークを使用せずに、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;
}

コードの説明#

  1. ソケットの作成

    • socket関数を使用して TCP ソケットを作成します。
  2. ソケットオプションの設定

    • setsockopt関数を使用してSO_REUSEADDRSO_REUSEPORTオプションを設定し、アドレスとポートの再利用を許可します。
  3. サーバーアドレス構造体

    • sockaddr_in構造体を使用してサーバーのアドレス情報を格納します。
    • INADDR_ANYは、サーバーが任意の IP アドレスの接続を受け入れることを示します。
  4. ソケットのバインド

    • bind関数を使用してソケットを指定されたアドレスとポートにバインドします。
  5. 接続のリッスン

    • listen関数を使用して接続のリッスンを開始します。パラメータ3は最大接続キューの長さを示します。
  6. 接続の受け入れ

    • accept関数を使用して incoming 接続を受け入れます。
  7. リクエストの受信

    • read関数を使用して接続からリクエストデータを読み取り、標準出力に印刷します。
  8. レスポンスの送信

    • シンプルな HTTP レスポンス文字列を構築し、send関数を使用してレスポンスを送信します。
  9. ソケットの閉鎖

    • close関数を使用して接続とリッスンソケットを閉じます。

コンパイルと実行#

上記のコードを http_server.cpp として保存し、次のように g++ でコンパイルして実行します:

g++ -o http_server http_server.cpp
./http_server

テスト#

ブラウザを開くか、curlを使用してサーバーをテストします:

curl http://localhost:8080

"こんにちは、世界!" というレスポンスが返ってくるはずです。

注意事項#

  • この例はデモ目的のみであり、実際のアプリケーションでは、複数の接続を処理するためのマルチスレッドまたは非同期処理、HTTP リクエストの解析、異なる HTTP メソッドやパスの処理など、より多くのエッジケースを処理する必要があります。
  • この例では、HTTP リクエストのヘッダーとボディの分離を処理していないため、実際のアプリケーションではより複雑な解析ロジックが必要になる場合があります。
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。