C++ implements websocket single server single client full duplex communication (based on boost!!!)

Own environment: ubuntu18.04 + gcc7.5.0 + boost1.7,3

Environment configuration

gcc or g++ are generally available, here mainly introduces the configuration method of boost
Execute the following code:

wget https://boostorg.jfrog.io/artifactory/main/release/1.73.0/source/boost_1_73_0.tar.bz2 --no-check-certificate
tar xvf boost_1_73_0.tar.bz2
cd boost_1_73_0
./bootstrap.sh --prefix=/usr
./b2
sudo ./b2 install
cat /usr/include/boost/version.hpp | grep "BOOST_LIB_VERSION"

After installation, it is found that an error will still be reported: #include no such file
Add another one at this time:

sudo apt-get install libboost-all-dev

Then compile and execute the code. I’m not sure whether to execute the apt-get. In theory, it’s no problem to compile the source code before. It’s probably the installation of the default library later, but I didn’t know too much about it at the time. Pay attention to the order, both of them have been done to succeed,
boost installation reference: https://blog.csdn.net/HandsomeHong/article/details/128813619

By the way, let me mention how to check the version of boost under Linux:

dpkg -S /usr/include/boost/version.hpp

Example source code

Client–client.h

#ifndef WEBSOCKET_CLIENT_H
#define WEBSOCKET_CLIENT_H
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <string>
#include <thread>
#include <codecvt>
#include <wchar.h>
#include <locale.h>
#include <stdlib.h>

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>

class Client {<!-- -->
    public:
        static std::wstring string_to_wstring(const std::string & str);
        static std::string wstring_to_string(const std::wstring & ws);
        static std::string ansi_to_utf8(const std::string & s);
        static std::string utf8_to_ansi(const std::string & s);
        static void connect(std::string IP, const char *port_s);
        static void send(std::string message);
        static void listen(std::string &out);
        static void disconnect();
};
    
#endif

Client–client.cpp

#include "client.h"

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>

net::io_context ioc;
tcp::resolver resolver{<!-- --> ioc };
websocket::stream<tcp::socket> ws{<!-- --> ioc };

std::wstring Client::string_to_wstring(const std::string & amp; str) {<!-- -->
    std::wstring r;
    const char *source = str.c_str();
    wchar_t *dest = NULL;
    int len = 0;
    int ret = 0;
    len = strlen(source) + 1;
    if(len <= 1)
        return 0;
    dest = new wchar_t[len];
    ret = mbstowcs(dest, source, len);
    r = std::wstring(dest);
    delete[] dest;
return r;
}

std::string Client::wstring_to_string(const std::wstring & amp; ws) {<!-- -->
    std::string r = "";
    const wchar_t *source = ws.c_str();
    char *dest = NULL;
    int len = 0;
    int ret = 0;
    len = wcslen(source) + 1;
    if(len <= 1)
        return 0;
    dest = new char[len*sizeof(wchar_t)];
    ret = wcstombs(dest, source, len*sizeof(wchar_t));
    r = std::string(dest);
    delete[] dest;
return r;
}

std::string Client::ansi_to_utf8(const std::string & amp; s) {<!-- -->
    static std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
return conv.to_bytes(string_to_wstring(s));
}

std::string Client::utf8_to_ansi(const std::string & s) {<!-- -->
    static std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
return wstring_to_string(conv. from_bytes(s));
}

void Client::connect(std::string IP, const char *port_s) {<!-- -->
try {<!-- -->
        auto const address = net::ip::make_address(IP); //server address
        auto const port = static_cast<unsigned short>(std::atoi(port_s));//server port number
        tcp::endpoint endpoint{<!-- --> address, port };
        auto const results = resolver. resolve(endpoint);
        // establish a connection on the IP address we got from the lookup
        net::connect(ws.next_layer(), results.begin(), results.end());
        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");
        }));
        std::cout << "The port is:" << port_s << std::endl;
        ws.handshake(IP, "/"); //Send handshake message
        std::cout << "The port:" << port_s << " finish!" << std::endl;
    }
    catch (std::exception const & e)
{<!-- -->
std::cerr << "Error: " << e.what() << std::endl;
return;
}
}

void Client::send(std::string message) {<!-- -->
    while (1) {<!-- -->
        //std::cout << "log:" << message << std::endl;
        ws.write(net::buffer(ansi_to_utf8(message)));
        sleep(1);
    }
}

void Client::listen(std::string & amp;out) {<!-- -->
    while (1) {<!-- -->
        beast::flat_buffer buffer;//Create a buffer for storing received messages
ws.read(buffer);// read a message to the buffer
out = beast::buffers_to_string(buffer.cdata());
//std::cout << utf8_to_ansi(out) << std::endl; //Output message to console display
    }
}

void Client::disconnect() {<!-- -->
    ws.close(websocket::close_code::normal);// close the WebSocket connection
}

Server-server.h

#ifndef WEBSOCKET_SERVER_H
#define WEBSOCKET_SERVER_H
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <thread>
#include <codecvt>
#include <wchar.h>
#include <locale.h>
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>

class Server {<!-- -->
    public:
        static std::wstring string_to_wstring(const std::string & str);
        static std::string wstring_to_string(const std::wstring & ws);
        static std::string ansi_to_utf8(const std::string & s);
        static std::string utf8_to_ansi(const std::string & s);
        static void do_session(tcp::socket & socket);
        static void initlization(std::string IP);
        static void initlization1(std::string IP);
};
#endif

Server-server.cpp

#include "server.h"

std::string send_message("server to client");

std::wstring Server::string_to_wstring(const std::string & str) {<!-- -->
    std::wstring r;
    const char *source = str.c_str();
    wchar_t *dest = NULL;
    int len = 0;
    int ret = 0;
    len = strlen(source) + 1;
    if(len <= 1)
        return 0;
    dest = new wchar_t[len];
    ret = mbstowcs(dest, source, len);
    r = std::wstring(dest);
    delete[] dest;
return r;
}

std::string Server::wstring_to_string(const std::wstring & ws) {<!-- -->
    std::string r = "";
    const wchar_t *source = ws.c_str();
    char *dest = NULL;
    int len = 0;
    int ret = 0;
    len = wcslen(source) + 1;
    if(len <= 1)
        return 0;
    dest = new char[len*sizeof(wchar_t)];
    ret = wcstombs(dest, source, len*sizeof(wchar_t));
    r = std::string(dest);
    delete[] dest;
return r;
}

std::string Server::ansi_to_utf8(const std::string & s) {<!-- -->
    static std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
return conv.to_bytes(string_to_wstring(s));
}

std::string Server::utf8_to_ansi(const std::string & s) {<!-- -->
    static std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
return wstring_to_string(conv. from_bytes(s));
}

// socket 20000 socket1 19999
void Server::do_session(tcp::socket & socket) {<!-- -->
    try
{<!-- -->
websocket::stream<tcp::socket> ws{<!-- --> std::move(socket) };
ws.set_option(websocket::stream_base::decorator(
[](websocket::response_type & res)
{<!-- -->
res.set(http::field::server,
std::string(BOOST_BEAST_VERSION_STRING) +
"websocket-server-sync");
}));
ws.accept();//wait for client connection
for (;;)
{<!-- -->
if (send_message != "")
ws.write(net::buffer(ansi_to_utf8(send_message)));

beast::flat_buffer buffer;// This buffer will hold incoming messages
ws.read(buffer);// read a message
auto out = beast::buffers_to_string(buffer.cdata());
if (out != "") {<!-- -->
std::cout << utf8_to_ansi(out) << std::endl;
}
sleep(1); //wait for 1 second
}
}
catch (beast::system_error const & se)
{<!-- -->
if (se. code() != websocket::error::closed)
std::cerr << "Error: " << se. code(). message() << std::endl;
}
catch (std::exception const & e)
{<!-- -->
std::cerr << "Error: " << e.what() << std::endl;
}
}

void Server::initlization(std::string IP) {<!-- -->
try
{<!-- -->
auto const address = net::ip::make_address(IP);//bind ip address
auto const port = static_cast<unsigned short>(std::atoi("20000"));//bind port number
net::io_context ioc{<!-- --> 1 };
tcp::acceptor acceptor{<!-- --> ioc,{<!-- --> address, port } };
for (;;)
{<!-- -->
tcp::socket socket{<!-- --> ioc };
acceptor. accept(socket);
// Open the thread and wait for the connection request from the client
std::thread{<!-- -->std::bind( & amp;do_session,std::move(socket)) }.detach();
}
}
catch (const std::exception & e) {<!-- -->
std::cerr << "Error: " << e.what() << std::endl;
return;
}
}

Client call – main_client.cpp

#include "client.h"

Client client1_listen;
Client client1_send;
Client client;
std::string listen_message = "";
std::string IP_server("192.168.1.116");
std::string send_message("client to server");
const char *port = "20000";

void listenThread() {<!-- -->
    // client1_listen.connect(IP_server, port_client1_listen);
    client. listen(listen_message);
}

void sendThread() {<!-- -->
    // client1_send.connect(IP_server, port_client1_send);
    client.send(send_message);
}

void outputThread() {<!-- -->
    while (1) {<!-- -->
        if (listen_message != "") {<!-- -->
            std::cout << listen_message << std::endl;
        }
        sleep(1);
    }
}

int main() {<!-- -->
    client.connect(IP_server, port);
    std::thread sendThreadObj(sendThread);
    std::thread listenThreadObj(listenThread);
    std::thread outputThreadObj(outputThread);
    listenThreadObj. join();
    sendThreadObj. join();
    outputThreadObj. join();
    return 0;
}

Server call – main_server.cpp

#include "server.h"
#include <iostream>
#include <thread>

// 20000 19999
int main() {<!-- -->
    Server server;
    std::string IP("192.168.1.116");
    server.initlization(IP);
    return 0;
}

Execution steps

g + + main_client.cpp client.cpp client.h -o client -std=c + + 11 -lpthread
g++ main_server.cpp server.cpp server.h -o server -std=c++11 -lpthread

Must first server and then client
./server
./client

Port 20000 is used for sending and receiving (can be changed by yourself)