从 C# UI 应用程序关闭阻止 webscokettpp 客户端的客户端连接

Posted

技术标签:

【中文标题】从 C# UI 应用程序关闭阻止 webscokettpp 客户端的客户端连接【英文标题】:Close blocking client connection of webscokettpp client from C# UI application 【发布时间】:2016-10-06 21:43:22 【问题描述】:

我正在使用 webscokettpp c++​​ 客户端来读取从网络服务器发布的数据。我有一个带有测试按钮的 c# UI 应用程序,它调用 c++ 客户端 dll 来获取和显示在套接字上发布的数据。单击测试按钮时,数据第二次在 UI 上正确发布我想关闭现有连接,打开新连接以再次获得结果。但是在第一次运行之后程序永远不会从 c.run(); 返回在下面的代码中。我正在使用来自https://github.com/zaphoyd/websocketpp/blob/master/examples/echo_client/echo_client.cpp的示例

 #include <websocketpp/config/asio_no_tls_client.hpp>
 #include <websocketpp/client.hpp>

 #include <iostream>

    typedef websocketpp::client<websocketpp::config::asio_client> client;

    using websocketpp::lib::placeholders::_1;
    using websocketpp::lib::placeholders::_2;
    using websocketpp::lib::bind;

    // pull out the type of messages sent by our config
    typedef websocketpp::config::asio_client::message_type::ptr message_ptr;

    // This message handler will be invoked once for each incoming message. It
    // prints the message and then sends a copy of the message back to the server.
    void on_message(client* c, websocketpp::connection_hdl hdl, message_ptr msg) 
        std::cout << "on_message called with hdl: " << hdl.lock().get()
                  << " and message: " << msg->get_payload()
                  << std::endl;

         if(pt.get<std::string>("test") = "close" )
          //Code reaches here after end of first run but never comes out of c.run()
            c->close(hdl, websocketpp::close::status::normal, "Success");
            hdl.reset();
         

        websocketpp::lib::error_code ec;

        c->send(hdl, msg->get_payload(), msg->get_opcode(), ec);
        if (ec) 
            std::cout << "Echo failed because: " << ec.message() << std::endl;
        
    

    int main(int argc, char* argv[]) 
        // Create a client endpoint
        client c;

        std::string uri = "ws://localhost:9002";

        if (argc == 2) 
            uri = argv[1];
        

        try 
            // Set logging to be pretty verbose (everything except message payloads)
            c.set_access_channels(websocketpp::log::alevel::all);
            c.clear_access_channels(websocketpp::log::alevel::frame_payload);

            // Initialize ASIO
            c.init_asio();

            // Register our message handler
            c.set_message_handler(bind(&on_message,&c,::_1,::_2));

            websocketpp::lib::error_code ec;
            client::connection_ptr con = c.get_connection(uri, ec);
            if (ec) 
                std::cout << "could not create connection because: " << ec.message() << std::endl;
                return 0;
            

            // Note that connect here only requests a connection. No network messages are
            // exchanged until the event loop starts running in the next line.
            c.connect(con);

            // Start the ASIO io_service run loop
            // this will cause a single connection to be made to the server. c.run()
            // will exit when this connection is closed.
            c.run();
         catch (websocketpp::exception const & e) 
            std::cout << e.what() << std::endl;
        
    

当条件 if(pt.get("test") = "close" ) 发生时,我正在尝试找出一种从 c.run() 中退出的 main 方法。

【问题讨论】:

我猜 echo_client 是为 echo_server 而不是任何网络服务器工作的。 错误,break? return? 【参考方案1】:

您需要在使用客户端时在单独的线程上调用 run();然后,当您在单独的线程上完成时,这将允许您优雅地停止客户端。 IIRC 然后 run() 将退出,这意味着您可以关闭线程并在需要时重新开始。

请参阅this FAQ,尤其是“我如何干净地退出基于 Asio 传输的程序”部分。停止 exe 以强制关闭连接是一个坏主意,可能会导致细微的错误。

基于 Asio 传输的客户端和服务器使用 Asio 库的底层 io_service 来处理异步网络操作。 io_service 的标准行为是运行直到没有异步操作,然后返回。 WebSocket++ 在使用 Asio 传输时,其行为类似于标准的 Asio 应用程序。如果您希望基于 WebSocket++/Asio 的程序停止网络操作并彻底关闭所有套接字,您需要执行以下操作:

对于服务器,调用 websocketpp::transport::asio::endpoint::stop_listening 来启动服务器监听套接字的关闭。 对于客户端,如果您使用 websocketpp::transport::asio::endpoint::start_perpetual 启用了永久模式,请使用 websocketpp::transport::asio::endpoint::stop_perpetual 禁用它。 对于两者,在所有当前未完成的连接上运行 websocketpp::endpoint::close 或 websocketpp::connection::close 。这将为这些连接启动 WebSocket 关闭握手 等待。 Asio 是异步的。当对上述方法(stop_listening、close 等)的调用完成时,服务器仍将处于侦听状态,连接仍将处于活动状态,直到 io_service 开始异步处理套接字和 WebSocket 协议关闭握手。 io_service::run 方法将在所有操作完成后自动干净地退出。 警告:Asio 的 io_service 有一个名为 stop 的方法。 WebSocket++ 将此方法包装为 websocketpp::transport::asio::endpoint::stop。尽管此操作听起来不错,但它是一种强大且具有破坏性的操作,仅应在特殊情况下使用。如果您使用 io_service::stop 或 endpoint::stop 没有很好的理由,您的程序可能会损坏并且可能表现出不稳定的行为。具体来说,io_service::stop 完全停止事件的处理。这不会给当前操作(例如套接字关闭握手)提供完成的机会。它将使您的套接字处于悬空状态,这可能会引发操作系统级别的超时或其他错误。

【讨论】:

以上是关于从 C# UI 应用程序关闭阻止 webscokettpp 客户端的客户端连接的主要内容,如果未能解决你的问题,请参考以下文章

C# 标签值发生变化,但 UI 上的文本没有 [关闭]

JetBrains Rider C# | Windows 窗体 UI [关闭]

iPhone 应用程序在从后台进入前台时会挂起/阻止 UI 几秒钟

C# 中 UI 线程和子进程之间的低延迟 IPC [关闭]

如何创建具有完全自定义用户界面的 C# 程序? [关闭]

防止kendo ui网格弹出编辑器在验证错误后关闭