mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-16 00:03:17 +00:00
Samples that did not compile or run as shown: - res.user_data.get<T>() inside a generic lambda needs the `template` keyword; use explicit parameter types (tour 09, cookbook s15). - listen() on a Unix domain socket fails with port 0 (tour 09, s22). - "*.dev.local" is not a NO_PROXY pattern (c16). - ssl_backend_error() holds a verify result, not an ERR_get_error() value, after a verification failure; decode each with the matching OpenSSL function (c18). - The content provider's `length` is everything that remains, so the sample read the whole file in one call (s05). Statements corrected: - Client keep-alive is off by default; c14 is rewritten around set_keep_alive(true). - Mounted files are looked up before GET handlers (tour 04, s04). - Params keep insertion order, and to_string(Error::Connection) reads "Could not establish connection" (tour 02). - A chunked provider ends with sink.done(), and post_routing_handler runs before the response is sent (tour 09). - Timeouts surface as Error::Read; Error::Timeout comes from the stream API (c17). The max timeout cuts off the wait for the response only (c13). The progress callback needs Content-Length (c11). - Encoding selection follows q-values, then Brotli, gzip, Zstd (s08), and the client compresses with the first of those it was built with (c15). - stop() cuts a provider-driven response short (s19); a rejected content_reader already gets 400 or 413 (s07); user_data values must be copyable (s12); Client accepts a client certificate too (t04); on_message() is the fallback for every unhandled event and 204/403/404 end reconnection (e04); the pong timeout takes two to three intervals and ends a waiting read() (w02). In the LLM app tutorial, an uncaught exception does not crash the server, so say what it does instead. Drop the server and client timeout settings whose stated purpose, covering inference and download time, they do not serve: those timeouts bound a single socket wait. Update the llama.cpp server layout in chapter 7.
2.7 KiB
2.7 KiB
title, order, status
| title | order | status |
|---|---|---|
| S22. Unix domain socketで通信する | 41 | draft |
ネットワーク経由ではなく、同じホスト内のプロセスとだけ通信したいときは、Unix domain socketを使えます。TCPのオーバーヘッドがなく、ファイルシステムのパーミッションで簡単にアクセス制御できるので、ローカルのIPCや、リバースプロキシの背後に置くサービスでよく使われます。
サーバー側
httplib::Server svr;
svr.set_address_family(AF_UNIX);
svr.Get("/", [](const auto &, auto &res) {
res.set_content("hello from unix socket", "text/plain");
});
svr.listen("/tmp/httplib.sock", 80);
set_address_family(AF_UNIX)を呼んでから、listen()の第1引数にソケットファイルのパスを渡します。第2引数のポート番号は使われませんが、シグネチャの都合で0以外の値を渡す必要があります(0だとlisten()が失敗します)。
クライアント側
httplib::Client cli("/tmp/httplib.sock");
cli.set_address_family(AF_UNIX);
auto res = cli.Get("/");
if (res) {
std::cout << res->body << std::endl;
}
Clientのコンストラクタにソケットファイルのパスを渡し、set_address_family(AF_UNIX)を呼ぶだけです。あとは通常のHTTPリクエストと同じように書けます。
使いどころ
- リバースプロキシとの連携: nginxがUnix socket経由でバックエンドを呼ぶ構成は、TCPより高速で、ポート管理も不要です
- ローカル専用API: 外部からアクセスしないツール間通信
- コンテナ内IPC: 同じPodやコンテナ内でのプロセス間通信
- 開発環境: ポート競合を気にしなくていい
ソケットファイルの後始末
Unix domain socketはファイルシステム上にファイルを作ります。サーバー終了時に自動では消えないので、必要なら起動前に削除しておきましょう。
std::remove("/tmp/httplib.sock");
svr.listen("/tmp/httplib.sock", 80);
パーミッション
ソケットファイルのパーミッションで、どのユーザーからアクセスできるかをコントロールできます。
svr.listen("/tmp/httplib.sock", 80);
// 別プロセスや別スレッドで
chmod("/tmp/httplib.sock", 0660); // オーナーとグループのみ
Warning: Windowsでも一部バージョンでAF_UNIXがサポートされていますが、実装や挙動がプラットフォームによって違います。クロスプラットフォームで動かす場合は、十分にテストしてから本番に投入してください。