0

I am using webscokettpp c++ client to read data posted from a web-server. I have a c# UI appication with a test button which calls c++ client dll to get and display the data posted on the socket. When test button is clicked data is posted properly on UI for second time I want to close existing connection, open new connection to get results again. But after the first run program never returns from c.run(); in following code. I am using a example from 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;
        }
    }

I am trying to figure out a way to main method to come out of c.run() when condition if(pt.get("test") = "close" ) happens.

DoIt
  • 313
  • 3
  • 12

1 Answers1

0

You need to call run() on a separate thread while you use the client; this will then allow you to stop the client gracefully when you are done on a separate thread. IIRC then run() will then exit meaning that you can close the thread and start all over again when you need to.

See this FAQ, particularly the "How do I cleanly exit an Asio transport based program" section. Stopping the exe to forcibly close the connection is a bad idea and can lead to subtle bugs.

The Asio transport based clients and servers use the Asio library's underlying io_service to handle asyncronous networking operations. The standard behavior of the io_service is to run until there are no async operations left and then return. WebSocket++, when using the Asio transport, behaves like a standard Asio application. If you want your WebSocket++/Asio based program to stop network operations and cleanly close all sockets you will want to do the following:

For servers, call websocketpp::transport::asio::endpoint::stop_listening to initiate the closing of the server listening socket. For clients, if you have engaged perpetual mode with websocketpp::transport::asio::endpoint::start_perpetual, disable it with websocketpp::transport::asio::endpoint::stop_perpetual. For both, run websocketpp::endpoint::close or websocketpp::connection::close on all currently outstanding connections. This will initiate the WebSocket closing handshake for these connections Wait. Asio is asyncronous. When the calls to the above methods (stop_listening, close, etc) complete the server will still be listening, the connections will still be active until the io_service gets around to asyncronously processing the socket and WebSocket protocol closing handshakes. The io_service::run method will exit cleanly and automatically when all operations are complete. WARNING: Asio's io_service has a method called stop. WebSocket++ wraps this method as websocketpp::transport::asio::endpoint::stop. While this operation has a benign sounding name, it is a powerful and destructive operation that should only be used in special cases. If you are using io_service::stop or endpoint::stop without a very good reason your program is likely broken and may exhibit erratic behavior. Specifically, io_service::stop stops the processing of events entirely. This does not give current operations (such as socket closing handshakes) the opportunity to finish. It will leave your sockets in a dangling state that may invoke operating system level timeouts or other errors.

Community
  • 1
  • 1
castro
  • 409
  • 3
  • 13