如何优雅地停止使用 nghttp2 asio 构建的 HTTP2 服务器

Posted

技术标签:

【中文标题】如何优雅地停止使用 nghttp2 asio 构建的 HTTP2 服务器【英文标题】:How to gracefully stop a HTTP2 server built with nghttp2 asio 【发布时间】:2019-04-05 10:47:09 【问题描述】:

我知道如何使用nghttp2 asio 库来构建 HTTP2 服务器和客户端应用程序。

documentation 表示有 stopjoin API 用于优雅地停止 HTTP2 服务器。

有没有使用stopjoin 的工作示例?特别是,一旦调用listen_and_serve,线程就会进入繁忙循环。是否建议从不同的线程调用stop?不幸的是,文档中没有给出任何线索或示例代码。

编辑:

这是一个工作程序,我试图在其中停止 SIGINT 上的服务器。

#include <iostream>
#include <thread>
#include <nghttp2/asio_http2_server.h>

using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;

nghttp2::asio_http2::server::http2 myserver;
void signalHandler( int signum ) 
  std::cout << "Interrupt signal (" << signum << ") received." << std::endl;
  myserver.stop();
  myserver.join();
  exit(0);


int main(int argc, char *argv[]) 
  signal(SIGINT, signalHandler);
  std::thread::id this_id = std::this_thread::get_id();
  std::cout << "Main thread running at " << this_id << std::endl;
  boost::system::error_code ec;

  myserver.handle("/api/ping", [](const request &req, const response &res) 
    std::thread::id this_id = std::this_thread::get_id();
    std::cout << "Ping Request received at " << this_id << std::endl;
    req.on_data([](const uint8_t *data, std::size_t len)
      std::cerr.write(reinterpret_cast<const char *>(data), len);
      std::cerr << std::endl;
    );
    res.write_head(200);
    res.end("hello, ping\n");
  );

  if (myserver.listen_and_serve(ec, "0.0.0.0", "8080")) 
    std::cerr << "error: " << ec.message() << std::endl;
  

在按下Control+C 后,执行挂起在myserver.stop()。我尝试仅使用 myserver.stop()myserver.join() 但没有任何改进。如果我像下面这样直接调用exit(0),服务器会因分段错误而停止。

void signalHandler( int signum ) 
  std::cout << "Interrupt signal (" << signum << ") received." << std::endl;
  myserver.stop();
  myserver.join();
  exit(0);

感谢任何帮助。

【问题讨论】:

【参考方案1】:

listen_and_serve中的asynchronous参数应设置为true,默认为asynchronous = false

请注意,服务器不会退出并在myserver.join() 上等待,直到最后一个客户端连接关闭。当您调用myserver.close() 时,服务器将停止接受新连接。

以下可行的解决方案:

#include <iostream>
#include <thread>
#include <nghttp2/asio_http2_server.h>

using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;

nghttp2::asio_http2::server::http2 myserver;
void signalHandler( int signum ) 
  std::cout << "Interrupt signal (" << signum << ") received." << std::endl;
  myserver.stop();


int main(int argc, char *argv[]) 
  signal(SIGINT, signalHandler);
  std::thread::id this_id = std::this_thread::get_id();
  boost::system::error_code ec;

  myserver.handle("/api/ping", [](const request &req, const response &res) 
    std::thread::id this_id = std::this_thread::get_id();
    std::cout << "Ping Request received at " << this_id << std::endl;
    req.on_data([](const uint8_t *data, std::size_t len)
      std::cerr.write(reinterpret_cast<const char *>(data), len);
      std::cerr << std::endl;
    );
    res.write_head(200);
    res.end("hello, ping\n");
  );

  if (myserver.listen_and_serve(ec, "0.0.0.0", "8080", true)) 
    std::cerr << "error: " << ec.message() << std::endl;
  
  myserver.join();

【讨论】:

以上是关于如何优雅地停止使用 nghttp2 asio 构建的 HTTP2 服务器的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 nghttp2 解决“空响应”错误?

如何优雅地关闭 boost asio ssl 客户端?

优雅地取消 boost::asio::async_read

nghttp2 多部分 POST 消息

Kubernetes 中如何保证优雅地停止 Pod

Kubernetes 中如何保证优雅地停止 Pod