如何优雅地停止 uWebSockets 服务器?

Posted

技术标签:

【中文标题】如何优雅地停止 uWebSockets 服务器?【英文标题】:How can I gracefully stop a uWebSockets server? 【发布时间】:2018-11-13 16:51:01 【问题描述】:

如何退出官方示例中的run() 调用?比如收到信号后。

uWS::SSLApp(

    /* There are tons of SSL options */
    .cert_file_name = "cert.pem",
    .key_file_name = "key.pem"

).onGet("/", [](auto *res, auto *req) 

    /* Respond with the web app on default route */
    res->writeStatus("200 OK")
       ->writeHeader("Content-Type", "text/html; charset=utf-8")
       ->end(indexHtmlBuffer);

).onWebSocket<UserData>("/ws/chat", [&](auto *ws, auto *req) 

    /* Subscribe to topic /chat */
    ws->subscribe("chat");

).onMessage([&](auto *ws, auto message, auto opCode) 

    /* Parse incoming message according to some protocol & publish it */
    if (seemsReasonable(message)) 
        ws->publish("chat", message);
     else 
        ws->close();
    

).onClose([&](auto *ws, int code, auto message) 

    /* Remove websocket from this topic */
    ws->unsubscribe("chat");

).listen("localhost", 3000, 0).run();

【问题讨论】:

@Vadim 有解决方案吗? @Vahagn 不,我刚刚编辑了问题 【参考方案1】:

在a documentation中,写着如下:

许多用户询问他们应该如何停止事件循环。事情不是这样的,你从不阻止它,你让它失败。通过关闭所有套接字、停止监听套接字、删除任何计时器等,循环将自动导致 App.run 正常返回,而不会出现内存泄漏。

由于应用程序本身受 RAII 控制,一旦阻塞的 .run 调用返回并且应用程序超出范围,所有内存将被优雅地删除。

所以这意味着你必须释放函数内部的每个源。所以例如这个:

    void testThread() 
        std::this_thread::sleep_for(15s);
        us_listen_socket_close(0, listen_socket);
    

    int main()
    
        std::thread thread(testThread);
        uWS::App app;
        /* Very simple WebSocket broadcasting echo server */
        app.ws<PerSocketData>("/*", 
            /* Settings */
            .compression = uWS::SHARED_COMPRESSOR,
            .maxPayloadLength = 16 * 1024 * 1024,
            .idleTimeout = 10,
            .maxBackpressure = 1 * 1024 * 1204,
            /* Handlers */
            .open = [](auto* ws, auto* req) 
                /* Let's make every connection subscribe to the "broadcast" topic */
                ws->subscribe("broadcast");
            ,
            .message = [](auto* ws, std::string_view message, uWS::OpCode opCode) 
            ,
            .drain = [](auto* ws) 
                /* Check getBufferedAmount here */
            ,
            .ping = [](auto* ws) 

            ,
            .pong = [](auto* ws) 

            ,
            .close = [](auto* ws, int code, std::string_view message) 
                std::cout << "Client disconnect!" << std::endl;

                /* We automatically unsubscribe from any topic here */
            
            ).listen(9001, [](auto* token) 
                listen_socket = token;
                if (token) 
                    std::cout << "Listening on port " << 9001 << std::endl;
                
                );
            app.run();

            std::cout << "Shutdown!" << std::endl;

并且在调用 testThread 之后,服务器应该退出(如果没有连接客户端,否则,您还应该断开连接的客户端(套接字))并在 run() 行之后继续。断开客户端后,我的输出如下:

监听 9001 端口

客户端断开连接!

客户端断开连接!

客户端断开连接!

客户端断开连接!

客户端断开连接!

客户端断开连接!

关机!

【讨论】:

你试过这个代码吗?当我试图通过单元测试反复设置服务器时,我所有的尝试都会导致服务器挂起。 目前没有,但现在可以,它可以工作,但它与上面的代码不同,因为我的版本有点不同。 我已经编辑了这个例子。这是我测试过的并且有效。我成功退出线程,控制台中有“关机”。

以上是关于如何优雅地停止 uWebSockets 服务器?的主要内容,如果未能解决你的问题,请参考以下文章

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

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

「SpringBoot」如何优雅地管理SpringBoot项目

SpringBoot系列: 如何优雅停止服务

SpringBoot系列: 如何优雅停止服务

如何优雅地关闭猫鼬的连接池?