Bladeren bron

Update documentation

yhirose 3 weken geleden
bovenliggende
commit
f15992c7ed

+ 19 - 0
README.md

@@ -347,6 +347,25 @@ int port = svr.bind_to_any_port("0.0.0.0");
 svr.listen_after_bind();
 ```
 
+### Port sharing and exclusive binding
+
+By default, the server socket enables address/port reuse: `SO_REUSEPORT` where it is available (Linux, macOS), and `SO_REUSEADDR` otherwise (Windows). A restarted server can bind again immediately, but binding to a port that another server is already listening on also succeeds, and connections are distributed between them.
+
+If you want `listen()` to fail when the port is already in use, replace the default socket options with `set_socket_options`:
+
+```cpp
+svr.set_socket_options([](socket_t sock) {
+#ifdef _WIN32
+  httplib::set_socket_opt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, 1);
+#else
+  httplib::set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+#endif
+});
+```
+
+> [!NOTE]
+> Setting only `SO_REUSEADDR` is not enough on Windows. There, `SO_REUSEADDR` allows two sockets that both set it to bind to the same port, so use `SO_EXCLUSIVEADDRUSE` instead.
+
 ### Static File Server
 
 ```cpp

+ 27 - 2
docs-src/pages/en/cookbook/s18-listen-after-bind.md

@@ -43,15 +43,40 @@ svr.listen_after_bind();
 
 ## Check the return values
 
-`bind_to_port()` returns `false` on failure — typically when the port is already taken. Always check it.
+`bind_to_port()` returns `false` on failure, for example when you don't have permission to bind to the port. Always check it.
 
 ```cpp
 if (!svr.bind_to_port("0.0.0.0", 8080)) {
-  std::cerr << "port already in use" << std::endl;
+  std::cerr << "bind failed" << std::endl;
   return 1;
 }
 ```
 
 `listen_after_bind()` blocks until the server stops and returns `true` on a clean shutdown.
 
+## Detect a port that's already in use
+
+With the default settings, you can actually bind to a port another server is already using. That's because cpp-httplib sets `SO_REUSEPORT` (Linux, macOS) or `SO_REUSEADDR` (Windows) on the server socket. A restarted server can bind again right away. The flip side is that a second server on the same port starts without an error, and connections get split between the two.
+
+To make `bind_to_port()` fail on a port in use, replace the socket options with `set_socket_options()`.
+
+```cpp
+svr.set_socket_options([](socket_t sock) {
+#ifdef _WIN32
+  httplib::set_socket_opt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, 1);
+#else
+  httplib::set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+#endif
+});
+
+if (!svr.bind_to_port("0.0.0.0", 8080)) {
+  std::cerr << "port already in use" << std::endl;
+  return 1;
+}
+```
+
+`set_socket_options()` replaces the defaults entirely. Setting `SO_REUSEADDR` on Linux and macOS keeps the "restarted server can bind again right away" behavior.
+
+> **Note:** `SO_REUSEADDR` alone isn't enough on Windows. Two sockets that both set it can bind to the same port, so use `SO_EXCLUSIVEADDRUSE` instead.
+
 > **Note:** To auto-pick a free port, see [S17. Bind to any available port](../s17-bind-any-port). Under the hood, that's just `bind_to_any_port()` + `listen_after_bind()`.

+ 27 - 2
docs-src/pages/ja/cookbook/s18-listen-after-bind.md

@@ -43,15 +43,40 @@ svr.listen_after_bind();
 
 ## 戻り値のチェック
 
-`bind_to_port()`は失敗すると`false`を返します。ポートが既に使われている場合などです。必ずチェックしてください。
+`bind_to_port()`は失敗すると`false`を返します。ポートにbindする権限が無い場合などです。必ずチェックしてください。
 
 ```cpp
 if (!svr.bind_to_port("0.0.0.0", 8080)) {
-  std::cerr << "port already in use" << std::endl;
+  std::cerr << "bind failed" << std::endl;
   return 1;
 }
 ```
 
 `listen_after_bind()`はサーバーが停止するまでブロックし、正常終了なら`true`を返します。
 
+## 使用中のポートを検出する
+
+実は、デフォルトの設定では、ほかのサーバーが使っているポートにもbindできてしまいます。cpp-httplibがサーバーソケットに`SO_REUSEPORT`(Linux、macOS)か`SO_REUSEADDR`(Windows)を設定しているからです。再起動したサーバーはすぐにbindし直せます。その代わり、同じポートで2つ目のサーバーを起動してもエラーにならず、接続が両方に振り分けられます。
+
+使用中のポートで`bind_to_port()`を失敗させたいときは、`set_socket_options()`でソケットオプションを差し替えてください。
+
+```cpp
+svr.set_socket_options([](socket_t sock) {
+#ifdef _WIN32
+  httplib::set_socket_opt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, 1);
+#else
+  httplib::set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+#endif
+});
+
+if (!svr.bind_to_port("0.0.0.0", 8080)) {
+  std::cerr << "port already in use" << std::endl;
+  return 1;
+}
+```
+
+`set_socket_options()`はデフォルトの設定を丸ごと置き換えます。Linux、macOSで`SO_REUSEADDR`を設定しているのは、再起動したサーバーがすぐにbindし直せるようにするためです。
+
+> **Note:** Windowsでは`SO_REUSEADDR`だけでは足りません。お互いに`SO_REUSEADDR`を設定したソケット同士は、同じポートにbindできてしまいます。`SO_EXCLUSIVEADDRUSE`を使ってください。
+
 > **Note:** 空いているポートを自動で選びたいときは[S17. ポートを動的に割り当てる](../s17-bind-any-port)を参照してください。こちらも内部では`bind_to_any_port()` + `listen_after_bind()`の組み合わせです。