Debian 12 Bookworm で確認しました。次のパッケージが前提です。
sudo apt install libuv1-dev libh2o-devH2O のバージョンは 2.2.5 です。
ビルドと実行です。
gcc -o h2o_server server.c -lh2o -luv -lssl -lcrypto -pthread
./h2o_server
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <signal.h> | |
| #include <netinet/in.h> | |
| #include <sys/socket.h> | |
| #include <uv.h> | |
| #include <h2o.h> | |
| #include <h2o/http1.h> | |
| static h2o_globalconf_t config; | |
| static h2o_context_t ctx; | |
| static h2o_accept_ctx_t accept_ctx; | |
| static uv_tcp_t listener; | |
| static int should_exit = 0; | |
| // ハンドラー関数:すべてのリクエストに対して "Hello, World!" を返す | |
| static int hello_handler(h2o_handler_t *self, h2o_req_t *req) | |
| { | |
| // GETメソッドのみ受け付ける | |
| if (!h2o_memis(req->method.base, req->method.len, H2O_STRLIT("GET"))) { | |
| return -1; // 他のハンドラーに処理を委ねる | |
| } | |
| // レスポンスヘッダーを設定 | |
| req->res.status = 200; | |
| req->res.reason = "OK"; | |
| h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_CONTENT_TYPE, | |
| NULL, H2O_STRLIT("text/plain; charset=utf-8")); | |
| // レスポンスボディを設定 | |
| const char *body_str = "Hello, World!\n"; | |
| h2o_iovec_t body = h2o_iovec_init(body_str, strlen(body_str)); | |
| h2o_send_inline(req, body.base, body.len); | |
| return 0; | |
| } | |
| // 新しい接続を受け入れる際のコールバック | |
| static void on_accept(uv_stream_t *server, int status) | |
| { | |
| if (status < 0) { | |
| fprintf(stderr, "New connection error %s\n", uv_strerror(status)); | |
| return; | |
| } | |
| uv_tcp_t *client = malloc(sizeof(uv_tcp_t)); | |
| uv_tcp_init(ctx.loop, client); | |
| if (uv_accept(server, (uv_stream_t*)client) == 0) { | |
| h2o_socket_t *sock = h2o_uv_socket_create((uv_stream_t*)client, NULL); | |
| h2o_accept(&accept_ctx, sock); | |
| } else { | |
| uv_close((uv_handle_t*)client, NULL); | |
| free(client); | |
| } | |
| } | |
| // シグナルコールバック | |
| static void signal_cb(uv_signal_t *handle, int signum) | |
| { | |
| should_exit = 1; | |
| uv_stop(ctx.loop); | |
| } | |
| int main(void) | |
| { | |
| struct sockaddr_in addr; | |
| uv_signal_t sig_int, sig_term; | |
| // H2Oの設定を初期化 | |
| h2o_config_init(&config); | |
| // ホストを作成(任意のホスト名でアクセス可能) | |
| h2o_hostconf_t *hostconf = h2o_config_register_host(&config, | |
| h2o_iovec_init(H2O_STRLIT("default")), | |
| 65535); | |
| // パスハンドラーを登録(すべてのパスに対して) | |
| h2o_pathconf_t *pathconf = h2o_config_register_path(hostconf, "/", 0); | |
| h2o_handler_t *handler = h2o_create_handler(pathconf, sizeof(*handler)); | |
| handler->on_req = hello_handler; | |
| // uvループを作成してコンテキストを初期化(ホスト設定後) | |
| uv_loop_t *loop = uv_default_loop(); | |
| h2o_context_init(&ctx, loop, &config); | |
| // アクセプトコンテキストを初期化 | |
| accept_ctx.ctx = &ctx; | |
| accept_ctx.hosts = config.hosts; | |
| // シグナルハンドラーを設定 | |
| uv_signal_init(loop, &sig_int); | |
| uv_signal_init(loop, &sig_term); | |
| uv_signal_start(&sig_int, signal_cb, SIGINT); | |
| uv_signal_start(&sig_term, signal_cb, SIGTERM); | |
| // TCPリスナーを初期化 | |
| uv_tcp_init(loop, &listener); | |
| // アドレスを設定 | |
| uv_ip4_addr("0.0.0.0", 8080, &addr); | |
| // バインド | |
| int r = uv_tcp_bind(&listener, (const struct sockaddr*)&addr, 0); | |
| if (r) { | |
| fprintf(stderr, "Bind error %s\n", uv_strerror(r)); | |
| return 1; | |
| } | |
| // リッスン開始 | |
| r = uv_listen((uv_stream_t*)&listener, 128, on_accept); | |
| if (r) { | |
| fprintf(stderr, "Listen error %s\n", uv_strerror(r)); | |
| return 1; | |
| } | |
| printf("HTTP server listening on http://localhost:8080/\n"); | |
| printf("Press Ctrl+C to stop\n"); | |
| // イベントループ実行 | |
| uv_run(loop, UV_RUN_DEFAULT); | |
| printf("\nShutting down...\n"); | |
| // クリーンアップ | |
| h2o_context_dispose(&ctx); | |
| h2o_config_dispose(&config); | |
| uv_loop_close(loop); | |
| return 0; | |
| } |