C or C++ websocket client working example

I am new to C and C++. I am trying to find small working example for any websocket library in C or C++ that can connect to websocket server. So, far I have explored, uWebsockets, libwebsockets, websocketpp, and boost::beast. None of them seem to have detailed documentation. I found some examples on boost::beast website at , however they are not working either. If I can find make a single working example I can work on it to learn more.

I tried this command, and it is connecting to yahoo endpoint: wscat -c "wss://" -H 'Origin: and print a random string.

wscat -c "wss://" -H 'Origin:
Connected (press CTRL+C to quit)
> {"subscribe":["ES=F","YM=F","NQ=F","RTY=F","CL=F","GC=F","SI=F","EURUSD=X","^TNX","^VIX","GBPUSD=X","JPY=X","BTC-USD","^CMC200","^FTSE","^N225","INTC"]}
< CgdCVEMtVVNEFduJQ0cYoP2/2/VeIgNVU0QqA0NDQzApOAFFlmEuP0iAgL/AwQJVlwxHR139ST1HZYBWqUNqC0JpdGNvaW4gVVNEsAGAgL/AwQLYAQTgAYCAv8DBAugBgIC/wMEC8gEDQlRD+gENQ29pbk1hcmtldENhcIECAAAAADbvcUGJAgAAhAG9ZWtC
< CgdCVEMtVVNEFQTtQkcY4KbH2/VeIgNVU0QqA0NDQzApOAFFUznHPkiAgMzPwQJVlwxHR139ST1HZQBrQUNqC0JpdGNvaW4gVVNEsAGAgMzPwQLYAQTgAYCAzM/BAugBgIDMz8EC8gEDQlRD+gENQ29pbk1hcmtldENhcIECAAAAADbvcUGJAgAAND7DT2tC

I tried simple python code like this

from websocket import create_connection
import json
import pprint
import re
import time
import datetime
def subscribe_yahoo (): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0', 'Accept': '*/*', 'Accept-Language': 'en-US,en;q=0.5', 'Sec-WebSocket-Version': '13', 'Origin': ' 'Sec-WebSocket-Key': 'nNtGm/0ZJcrR+goawlJz9w==', 'DNT': '1', 'Connection': 'keep-alive, Upgrade', 'Sec-Fetch-Dest': 'websocket', 'Sec-Fetch-Mode': 'websocket' , 'Sec-Fetch-Site': 'same-site' , 'Pragma': 'no-cache', 'Cache-Control': 'no-cache', 'Upgrade': 'websocket', } messages='{"subscribe":["INTC"]}' # Initialize the headers needed for the websocket connection initMessages = [ messages, ] websocketUri = """wss://""" print (websocketUri) ws = create_connection(websocketUri,header=headers) for m in initMessages: print ("sending ", m) ws.send(m) message_stream = True i=0 while message_stream: result = ws.recv() i=i+1 print (str(i),' -- ', result)
subscribe_yahoo()

and it is working too.

I would really appreciate if someone can help me with a code that works similarly in c or c++.

Can someone explain if it is possible to use firefox source code to implement a websocket client in C++ or not, or if someone has used firefox code successfully for websocket client.

I haven't asked for any recommended library, any library will do for my learning purpose. Thanks in advance :)

Following example is copied as is from

#include "example/common/root_certificates.hpp"
#include <boost/beast/core.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/websocket/ssl.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.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>
namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.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-ssl <host> <port> <text>\n" << "Example:\n" << " websocket-client-sync-ssl echo.websocket.org 443 \"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; // The SSL context is required, and holds certificates ssl::context ctx{ssl::context::tlsv12_client}; // This holds the root certificate used for verification load_root_certificates(ctx); // These objects perform our I/O tcp::resolver resolver{ioc}; websocket::stream<beast::ssl_stream<tcp::socket>> ws{ioc, ctx}; // 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(get_lowest_layer(ws), results); // Set SNI Hostname (many hosts need this to handshake successfully) if(! SSL_set_tlsext_host_name(ws.next_layer().native_handle(), host.c_str())) throw beast::system_error( beast::error_code( static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()), "Failed to set SNI Hostname"); // Update the host_ string. This will provide the value of the // Host HTTP header during the WebSocket handshake. // See host += ':' + std::to_string(ep.port()); // Perform the SSL handshake ws.next_layer().handshake(ssl::stream_base::client); // 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;
}

Compiled using :

g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
g++ boost_test.cpp -o websocket-client-sync-ssl -lboost_system -pthread -lssl -lcrypto
./websocket-client-sync-ssl
Usage: websocket-client-sync-ssl <host> <port> <text>
Example: websocket-client-sync-ssl echo.websocket.org 443 "Hello, world!"

then as suggested:

./websocket-client-sync-ssl echo.websocket.org 443 "Hello, world!"

doesn't work

/websocket-client-sync-ssl streamer.finance.yahoo.com 443 "Hello, world!"
Error: The WebSocket stream was gracefully closed at both endpoints
7

1 Answer

Here's a quick demo using easywsclient:

#include "easywsclient.hpp"
#include <iostream>
#include <string>
#include <memory>
#include <mutex>
#include <deque>
#include <thread>
#include <chrono>
#include <atomic>
// a simple, thread-safe queue with (mostly) non-blocking reads and writes
namespace non_blocking {
template <class T>
class Queue { mutable std::mutex m; std::deque<T> data;
public: void push(T const &input) { std::lock_guard<std::mutex> L(m); data.push_back(input); } bool pop(T &output) { std::lock_guard<std::mutex> L(m); if (data.empty()) return false; output = data.front(); data.pop_front(); return true; }
};
}
// eastwsclient isn't thread safe, so this is a really simple
// thread-safe wrapper for it.
class Ws { std::thread runner; non_blocking::Queue<std::string> outgoing; non_blocking::Queue<std::string> incoming; std::atomic<bool> running { true };
public: void send(std::string const &s) { outgoing.push(s); } bool recv(std::string &s) { return incoming.pop(s); } Ws(std::string url) { using easywsclient::WebSocket; runner = std::thread([=] { std::unique_ptr<WebSocket> ws(WebSocket::from_url(url)); while (running) { if (ws->getReadyState() == WebSocket::CLOSED) break; std::string data; if (outgoing.pop(data)) ws->send(data); ws->poll(); ws->dispatch([&](const std::string & message) { incoming.push(message); }); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } ws->close(); ws->poll(); }); } void close() { running = false; } ~Ws() { if (runner.joinable()) runner.join(); }
};
int main() { Ws socket("ws://localhost:40800"); std::atomic<bool> run{true}; auto receiver = std::thread([&] { std::string s; while (run) { if (socket.recv(s)) std::cout << s << '\n'; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } }); std::string line; while (std::getline(std::cin, line)) socket.send(line); run = false; receiver.join(); socket.close();
}

I tested it with a server using Crow:

// A simple websocket-based echo server
#include "crow_all.h"
int main() { crow::SimpleApp app; CROW_ROUTE(app, "/") .websocket() .onopen([&](crow::websocket::connection& conn){ CROW_LOG_INFO << "new websocket connection"; }) .onclose([&](crow::websocket::connection& conn, const std::string& reason){ CROW_LOG_INFO << "websocket connection closed: " << reason; }) .onmessage([&](crow::websocket::connection& conn, const std::string& data, bool is_binary){ std::cout << "Received message: " << data << "\n"; if (is_binary) conn.send_binary(data); else conn.send_text(data); }); app.port(40800) .multithreaded() .run();
}

I built using this Makefile:

both: client server
INC = -Iexternal/easywsclient/ -Iexternal/crow/build/amalgamate/
LIBS = -leasywsclient -Lexternal/easywsclient -lboost_system -pthread
CXXFLAGS += ${INC}
client: client.o ${CXX} -o client client.o ${LIBS}
server: server.o ${CXX} -o server server.o ${LIBS}

To test, start the server, then the client. Then you can type random stuff into the client. It'll be sent to the server, printed out there, echoed back to the client, and printed back out there. Pretty much your typical, useless (but enough to prove they're communicating) network demo kind of thing.

6

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like