Files
cpp-httplib/docs-src/pages/ja/cookbook/w02-websocket-ping.md
yhirose bef278e0d2 Fix docs pages that no longer match the code
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.
2026-10-08 20:39:13 -04:00

4.8 KiB
Raw Blame History

title, order, status
title order status
W02. ハートビートを設定する 53 draft

WebSocket接続は長時間つなぎっぱなしになるので、プロキシやロードバランサが「アイドルだから」と勝手に切ってしまうことがあります。これを防ぐために、定期的にPingフレームを送って接続を生かしておく仕組みがあります。cpp-httplibでは、指定した間隔で自動的にPingを送ってくれます。

サーバー側の設定

svr.set_websocket_ping_interval(30); // 30秒ごとにPing

svr.WebSocket("/chat", [](const auto &req, auto &ws) {
  // ...
});

set_websocket_ping_interval()に秒数を渡すだけです。このサーバーが受け入れるすべてのWebSocket接続に対して、指定した間隔でPingが送られます。

std::chronoの期間を受け取るオーバーロードもあります。

using namespace std::chrono_literals;
svr.set_websocket_ping_interval(30s);

クライアント側の設定

クライアント側でも同じAPIがあります。

httplib::ws::WebSocketClient cli("ws://localhost:8080/chat");
cli.set_websocket_ping_interval(30);
cli.connect();

connect()を呼ぶ前に設定しておきましょう。

デフォルト値

デフォルトのPing間隔は、ビルド時のマクロCPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECONDで決まります。通常はそのままで問題ありませんが、特別なプロキシ環境に合わせて短くしたい場合は調整してください。

PongはどうやってpIngに応答するか

WebSocketプロトコルでは、PingフレームにはPongフレームで応答することが決まっています。cpp-httplibは受信したPingに自動でPongを返すので、アプリケーションコード側で気にする必要はありません。

Pingの間隔をどう決めるか

環境 推奨
通常のインターネット接続 30〜60秒
厳しいプロキシ(AWS ALBなど) 15〜30秒
モバイル回線 短すぎるとバッテリーを食う、60秒以上

短すぎると無駄なトラフィックになり、長すぎると接続が切れます。だいたい接続が切れる時間の半分くらいが目安です。

Warning: Ping間隔を極端に短くすると、WebSocket接続ごとにバックグラウンドでスレッドが走るので、CPU負荷が上がります。接続数が多いサーバーでは控えめな値に設定しましょう。

無応答のピアを検出する

Pingを送るだけでは、相手が「黙って落ちた」場合に気付けません。TCPの接続自体は生きているように見えるのに、相手のプロセスはもう応答しない、というケースです。これを検出するには、送ったPingに対してPongがN回連続で返ってこなかったら接続を切る、というオプションを有効にします。

cli.set_websocket_max_missed_pongs(2); // 2回連続でPongが返ってこなければ切断

サーバー側にも同じset_websocket_max_missed_pongs()があります。

たとえばPing間隔が30秒でmax_missed_pongs = 2なら、無応答のピアは応答が止まってから60〜90秒で検出され、CloseStatus::GoingAway(理由は"pong timeout")で接続が閉じられます。そのときread()で待っていた呼び出しはFailを返します。

この仕組みはread()を呼んでPongフレームを消費したタイミングでカウンタがリセットされます。つまり通常のWebSocketクライアントのようにread()をループで回していれば、特に意識することなく動きます。

デフォルトは無効

max_missed_pongsのデフォルトは0で、これは「Pongが何回返ってこなくてもこの仕組みでは切断しない」という意味です。Ping自体は送られ続けますが、応答の有無はチェックされません。無応答ピアを検出したい場合は明示的に1以上を設定してください。

サーバ側は0のままでも接続が残り続けることはありません。ハンドラがread()を呼んでいる間はCPPHTTPLIB_WEBSOCKET_SERVER_READ_TIMEOUT_SECOND(デフォルト300秒 = 5分)が保険として働きます。一方クライアント側にはこの保険がなく、読み取りタイムアウトを設定しない限り無期限に待つので、無応答ピアを検出する手段はmax_missed_pongsだけです。どちらの側でも「もっと速く検出したい」ときに使うオプションでもあります。

接続が閉じたときの処理はW03. 接続クローズをハンドリングするを参照してください。