8

I posted a question earlier asking why does my server (written in C++ and boost::asio) can't connect with a client (written in Javascript). Is the problem that the Javascript Websockets are different than boost::asio sockets ? Does boost::asio not support websockets ? What is the easiest way to work this out ?

Community
  • 1
  • 1
dimitris93
  • 4,155
  • 11
  • 50
  • 86
  • 1
    Your best bet is probably [websocket++](https://github.com/zaphoyd/websocketpp). It has a `boost::asio` transport. As it is, you need to write your own websocket protocol code on top of `asio`, or use an existing library like websocket++. – Sean Cline Apr 11 '16 at 23:49
  • @SeanCline Can I not make javascript work with sockets instead ? – dimitris93 Apr 11 '16 at 23:51
  • @Shiro See [this question](http://stackoverflow.com/q/1736382/3962537) about that. – Dan Mašek Apr 11 '16 at 23:54
  • @DanMašek Let me ask a different question. Is it lame to use websockets instead of sockets to communicate with a c++ application on a server and an android application in java ? – dimitris93 Apr 11 '16 at 23:56
  • @Shiro I'm not familiar with the exact criteria to evaluate lameness, but depending on circumstances it might not be the best design decision. I'm not an android developer, but since you mention Java, a quick search nets [this](http://developer.android.com/reference/java/net/Socket.html). However, let's say you wanted to have support for both java apps, as well as some web-based application. In that case building your protocol on top of websockets might be a good choice. – Dan Mašek Apr 12 '16 at 00:02
  • 1
    @DanMašek Yes, the problem is that I want to have support on android as well as browser. This is why I am thinking how will I make this work. – dimitris93 Apr 12 '16 at 00:03
  • @Shiro In that case, I'd probably choose websockets, just so that there's only one server implementation to deal with. On Android, I'd probably look for some [Java implementation of websockets](https://github.com/TooTallNate/Java-WebSocket), so you don't need to do the communications in JS. – Dan Mašek Apr 12 '16 at 00:09
  • 1
    @DanMašek For the record, `Wesocketpp` worked perfectly. Thank you. It is by far the easiest way to use websockets in C++. First install `boost` and then add `Websocketpp` as a header-only library to a project. – dimitris93 Apr 13 '16 at 12:02

1 Answers1

10

Boost.Beast, now part of Boost, is built on top of Boost.Asio and works the way you expect. It comes with example code and documentation. Check it out here: www.boost.org/libs/beast

Here's a complete program that sends a message to the echo server:

#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <cstdlib>
#include <iostream>
#include <string>

namespace beast = boost::beast;         // from <boost/beast.hpp>
namespace http = beast::http;           // from <boost/beast/http.hpp>
namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
namespace net = boost::asio;            // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp>

// Sends a WebSocket message and prints the response
int main(int argc, char** argv)
{
    try
    {
        // Check command line arguments.
        if(argc != 4)
        {
            std::cerr <<
                "Usage: websocket-client-sync <host> <port> <text>\n" <<
                "Example:\n" <<
                "    websocket-client-sync echo.websocket.org 80 \"Hello, world!\"\n";
            return EXIT_FAILURE;
        }
        std::string host = argv[1];
        auto const  port = argv[2];
        auto const  text = argv[3];

        // The io_context is required for all I/O
        net::io_context ioc;

        // These objects perform our I/O
        tcp::resolver resolver{ioc};
        websocket::stream<tcp::socket> ws{ioc};

        // Look up the domain name
        auto const results = resolver.resolve(host, port);

        // Make the connection on the IP address we get from a lookup
        auto ep = net::connect(ws.next_layer(), results);

        // Update the host_ string. This will provide the value of the
        // Host HTTP header during the WebSocket handshake.
        // See https://tools.ietf.org/html/rfc7230#section-5.4
        host += ':' + std::to_string(ep.port());

        // Set a decorator to change the User-Agent of the handshake
        ws.set_option(websocket::stream_base::decorator(
            [](websocket::request_type& req)
            {
                req.set(http::field::user_agent,
                    std::string(BOOST_BEAST_VERSION_STRING) +
                        " websocket-client-coro");
            }));

        // Perform the websocket handshake
        ws.handshake(host, "/");

        // Send the message
        ws.write(net::buffer(std::string(text)));

        // This buffer will hold the incoming message
        beast::flat_buffer buffer;

        // Read a message into our buffer
        ws.read(buffer);

        // Close the WebSocket connection
        ws.close(websocket::close_code::normal);

        // If we get here then the connection is closed gracefully

        // The make_printable() function helps print a ConstBufferSequence
        std::cout << beast::make_printable(buffer.data()) << std::endl;
    }
    catch(std::exception const& e)
    {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
Vinnie Falco
  • 5,173
  • 28
  • 43