如何使用boost::beast检测WebSocket断开?读写间隔期检测问询
Great question—this is a super common pain point when working with async WebSocket setups where you don't have an immediate write pending after a read. Let's break down the most reliable, practical approaches to handle this:
1. Use WebSocket's Native Ping/Pong Heartbeats
This is the gold standard because it's part of the WebSocket specification and works at the application layer, making it cross-platform and fully controllable. Here's how it works:
- Your server periodically sends a
Pingframe to the client usingasync_write. - The client is required by the spec to respond with a
Pongframe immediately. - Set up a timer (using your async framework's timer utilities) after sending each Ping. If the timer expires before you receive a corresponding Pong, you can safely assume the client has disconnected.
- Pro tip: Tune the interval based on your use case—10-30 seconds is typical for most applications to balance responsiveness and resource usage. Avoid overly frequent pings, as they can add unnecessary overhead.
2. Enable TCP Keepalive at the Socket Level
Let the operating system handle dead connection detection by enabling TCP keepalive. This works below the WebSocket layer, so it's a good fallback if you don't want to implement full Ping/Pong logic:
- You'll need to set socket options like
SO_KEEPALIVE, along with parameters likeTCP_KEEPIDLE(how long to wait before sending the first keepalive probe),TCP_KEEPINTVL(interval between probes), andTCP_KEEPCNT(number of failed probes before declaring the connection dead). - For example, in Boost.Asio, you might do something like this:
boost::asio::socket_base::keep_alive option(true); socket.set_option(option); // On Linux, tweak keepalive parameters via setsockopt int keepidle = 30; // 30 seconds of idle before first probe int keepintvl = 5; // 5 seconds between probes int keepcnt = 3; // 3 failed probes = connection dead setsockopt(socket.native_handle(), IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle)); setsockopt(socket.native_handle(), IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(keepintvl)); setsockopt(socket.native_handle(), IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt)); - Note: Default keepalive timings are often very long (e.g., 2 hours on some systems), so you'll need to adjust them to get reasonable detection latency.
3. Leverage Connection State Callbacks (If Your Library Supports It)
Most mature WebSocket libraries (like WebSocket++, libwebsockets, or Node.js' ws module) provide built-in callbacks for connection state changes. Look for callbacks named on_close, on_error, or on_disconnect—these will fire automatically when the client disconnects, regardless of whether you have pending read/write operations.
- This is the lowest-effort option if your framework supports it. Just register the callback and handle cleanup/notification logic there.
4. Initiate a "No-Op" Async Write (Carefully)
Some frameworks allow you to send a zero-length or empty WebSocket frame via async_write. Even though this doesn't transmit meaningful data, it will trigger an error callback immediately if the connection is dead.
- Caveat: Not all WebSocket implementations allow empty frames (some strictly adhere to the spec which requires non-empty payloads for certain frame types). Test this thoroughly with your library before relying on it.
Final Recommendation
Start with WebSocket Ping/Pong heartbeats—it's the most reliable and spec-compliant method. Pair it with TCP keepalive as a safety net for cases where the application layer might fail. If your library has connection state callbacks, definitely use those to simplify your code.
内容的提问来源于stack exchange,提问作者Robin Lew

