Ultra fast and low latency asynchronous socket server & client C++ library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and 10K connections problem solution

Overview

CppServer

Awesome C++ Linux build status OSX build status MinGW build status Windows build status

Ultra fast and low latency asynchronous socket server & client C++ library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and 10K connections problem solution.

CppServer API reference

Contents

Features

Requirements

Optional:

How to build?

Install gil (git links) tool

pip3 install gil

Setup repository

git clone https://github.com/chronoxor/CppServer.git
cd CppServer
gil update

Linux

cd build
./unix.sh

OSX

cd build
./unix.sh

Windows (MinGW)

cd build
mingw.bat

Windows (Visual Studio)

cd build
vs.bat

Examples

Example: Asio service

Asio service is used to host all clients/servers based on Asio C++ library. It is implemented based on Asio C++ Library and use a separate thread to perform all asynchronous IO operations and communications.

The common usecase is to instantiate one Asio service, start the service and attach TCP/UDP/WebSocket servers or/and clients to it. One Asio service can handle several servers and clients asynchronously at the same time in one I/O thread. If you want to scale your servers or clients it is possible to create and use more than one Asio services to handle your servers/clients in balance.

Also it is possible to dispatch or post your custom handler into I/O thread. Dispatch will execute the handler immediately if the current thread is I/O one. Otherwise the handler will be enqueued to the I/O queue. In opposite the post method will always enqueue the handler into the I/O queue.

Here comes an example of using custom Asio service with dispatch/post methods:

#include "server/asio/service.h"
#include "threads/thread.h"

#include <iostream>

int main(int argc, char** argv)
{
    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Dispatch
    std::cout << "1 - Dispatch from the main thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl;
    service->Dispatch([service]()
    {
        std::cout << "1.1 - Dispatched in thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl;

        std::cout << "1.2 - Dispatch from thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl;
        service->Dispatch([service]()
        {
            std::cout << "1.2.1 - Dispatched in thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl;
        });

        std::cout << "1.3 - Post from thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl;
        service->Post([service]()
        {
            std::cout << "1.3.1 - Posted in thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl;
        });
    });

    // Post
    std::cout << "2 - Post from the main thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl;
    service->Post([service]()
    {
        std::cout << "2.1 - Posted in thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl;

        std::cout << "2.2 - Dispatch from thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl;
        service->Dispatch([service]()
        {
            std::cout << "2.2.1 - Dispatched in thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl;
        });

        std::cout << "2.3 - Post from thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl;
        service->Post([service]()
        {
            std::cout << "2.3.1 - Posted in thread with Id " << CppCommon::Thread::CurrentThreadId() << std::endl;
        });
    });

    // Wait for a while...
    CppCommon::Thread::Sleep(1000);

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Output of the above example is the following:

Asio service started!
1 - Dispatch from the main thread with Id 16744
2 - Post from the main thread with Id 16744
1.1 - Dispatched in thread with Id 19920
1.2 - Dispatch from thread with Id 19920
1.2.1 - Dispatched in thread with Id 19920
1.3 - Post from thread with Id 19920
2.1 - Posted in thread with Id 19920
2.2 - Dispatch from thread with Id 19920
2.2.1 - Dispatched in thread with Id 19920
2.3 - Post from thread with Id 19920
1.3.1 - Posted in thread with Id 19920
2.3.1 - Posted in thread with Id 19920
Asio service stopped!

Example: Asio timer

Here comes the example of Asio timer. It can be used to wait for some action in future with providing absolute time or relative time span. Asio timer can be used in synchronous or asynchronous modes.

#include "server/asio/timer.h"
#include "threads/thread.h"

#include <iostream>

class AsioTimer : public CppServer::Asio::Timer
{
public:
    using CppServer::Asio::Timer::Timer;

protected:
    void onTimer(bool canceled) override
    {
        std::cout << "Asio timer " << (canceled ? "canceled" : "expired") << std::endl;
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Asio timer caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

int main(int argc, char** argv)
{
    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create a new Asio timer
    auto timer = std::make_shared<AsioTimer>(service);

    // Setup and synchronously wait for the timer
    timer->Setup(CppCommon::UtcTime() + CppCommon::Timespan::seconds(1));
    timer->WaitSync();

    // Setup and asynchronously wait for the timer
    timer->Setup(CppCommon::Timespan::seconds(1));
    timer->WaitAsync();

    // Wait for a while...
    CppCommon::Thread::Sleep(2000);

    // Setup and asynchronously wait for the timer
    timer->Setup(CppCommon::Timespan::seconds(1));
    timer->WaitAsync();

    // Wait for a while...
    CppCommon::Thread::Sleep(500);

    // Cancel the timer
    timer->Cancel();

    // Wait for a while...
    CppCommon::Thread::Sleep(500);

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Output of the above example is the following:

Asio service starting...Done!
Timer was expired
Timer was canceled
Asio service stopping...Done!

Example: TCP chat server

Here comes the example of the TCP chat server. It handles multiple TCP client sessions and multicast received message from any session to all ones. Also it is possible to send admin message directly from the server.

#include "server/asio/tcp_server.h"
#include "threads/thread.h"

#include <iostream>

class ChatSession : public CppServer::Asio::TCPSession
{
public:
    using CppServer::Asio::TCPSession::TCPSession;

protected:
    void onConnected() override
    {
        std::cout << "Chat TCP session with Id " << id() << " connected!" << std::endl;

        // Send invite message
        std::string message("Hello from TCP chat! Please send a message or '!' to disconnect the client!");
        SendAsync(message);
    }

    void onDisconnected() override
    {
        std::cout << "Chat TCP session with Id " << id() << " disconnected!" << std::endl;
    }

    void onReceived(const void* buffer, size_t size) override
    {
        std::string message((const char*)buffer, size);
        std::cout << "Incoming: " << message << std::endl;

        // Multicast message to all connected sessions
        server()->Multicast(message);

        // If the buffer starts with '!' the disconnect the current session
        if (message == "!")
            DisconnectAsync();
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Chat TCP session caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

class ChatServer : public CppServer::Asio::TCPServer
{
public:
    using CppServer::Asio::TCPServer::TCPServer;

protected:
    std::shared_ptr<CppServer::Asio::TCPSession> CreateSession(std::shared_ptr<CppServer::Asio::TCPServer> server) override
    {
        return std::make_shared<ChatSession>(server);
    }

protected:
    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Chat TCP server caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

int main(int argc, char** argv)
{
    // TCP server port
    int port = 1111;
    if (argc > 1)
        port = std::atoi(argv[1]);

    std::cout << "TCP server port: " << port << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create a new TCP chat server
    auto server = std::make_shared<ChatServer>(service, port);

    // Start the server
    std::cout << "Server starting...";
    server->Start();
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Restart the server
        if (line == "!")
        {
            std::cout << "Server restarting...";
            server->Restart();
            std::cout << "Done!" << std::endl;
            continue;
        }

        // Multicast admin message to all sessions
        line = "(admin) " + line;
        server->Multicast(line);
    }

    // Stop the server
    std::cout << "Server stopping...";
    server->Stop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: TCP chat client

Here comes the example of the TCP chat client. It connects to the TCP chat server and allows to send message to it and receive new messages.

#include "server/asio/tcp_client.h"
#include "threads/thread.h"

#include <atomic>
#include <iostream>

class ChatClient : public CppServer::Asio::TCPClient
{
public:
    ChatClient(std::shared_ptr<CppServer::Asio::Service> service, const std::string& address, int port)
        : CppServer::Asio::TCPClient(service, address, port)
    {
        _stop = false;
    }

    void DisconnectAndStop()
    {
        _stop = true;
        DisconnectAsync();
        while (IsConnected())
            CppCommon::Thread::Yield();
    }

protected:
    void onConnected() override
    {
        std::cout << "Chat TCP client connected a new session with Id " << id() << std::endl;
    }

    void onDisconnected() override
    {
        std::cout << "Chat TCP client disconnected a session with Id " << id() << std::endl;

        // Wait for a while...
        CppCommon::Thread::Sleep(1000);

        // Try to connect again
        if (!_stop)
            ConnectAsync();
    }

    void onReceived(const void* buffer, size_t size) override
    {
        std::cout << "Incoming: " << std::string((const char*)buffer, size) << std::endl;
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Chat TCP client caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }

private:
    std::atomic<bool> _stop;
};

int main(int argc, char** argv)
{
    // TCP server address
    std::string address = "127.0.0.1";
    if (argc > 1)
        address = argv[1];

    // TCP server port
    int port = 1111;
    if (argc > 2)
        port = std::atoi(argv[2]);

    std::cout << "TCP server address: " << address << std::endl;
    std::cout << "TCP server port: " << port << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create a new TCP chat client
    auto client = std::make_shared<ChatClient>(service, address, port);

    // Connect the client
    std::cout << "Client connecting...";
    client->ConnectAsync();
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Disconnect the client
        if (line == "!")
        {
            std::cout << "Client disconnecting...";
            client->DisconnectAsync();
            std::cout << "Done!" << std::endl;
            continue;
        }

        // Send the entered text to the chat server
        client->SendAsync(line);
    }

    // Disconnect the client
    std::cout << "Client disconnecting...";
    client->DisconnectAndStop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: SSL chat server

Here comes the example of the SSL chat server. It handles multiple SSL client sessions and multicast received message from any session to all ones. Also it is possible to send admin message directly from the server.

This example is very similar to the TCP one except the code that prepares SSL context and handshake handler.

#include "server/asio/ssl_server.h"
#include "threads/thread.h"

#include <iostream>

class ChatSession : public CppServer::Asio::SSLSession
{
public:
    using CppServer::Asio::SSLSession::SSLSession;

protected:
    void onConnected() override
    {
        std::cout << "Chat SSL session with Id " << id() << " connected!" << std::endl;
    }

    void onHandshaked() override
    {
        std::cout << "Chat SSL session with Id " << id() << " handshaked!" << std::endl;

        // Send invite message
        std::string message("Hello from SSL chat! Please send a message or '!' to disconnect the client!");
        SendAsync(message.data(), message.size());
    }

    void onDisconnected() override
    {
        std::cout << "Chat SSL session with Id " << id() << " disconnected!" << std::endl;
    }

    void onReceived(const void* buffer, size_t size) override
    {
        std::string message((const char*)buffer, size);
        std::cout << "Incoming: " << message << std::endl;

        // Multicast message to all connected sessions
        server()->Multicast(message);

        // If the buffer starts with '!' the disconnect the current session
        if (message == "!")
            DisconnectAsync();
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Chat SSL session caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

class ChatServer : public CppServer::Asio::SSLServer
{
public:
    using CppServer::Asio::SSLServer::SSLServer;

protected:
    std::shared_ptr<CppServer::Asio::SSLSession> CreateSession(std::shared_ptr<CppServer::Asio::SSLServer> server) override
    {
        return std::make_shared<ChatSession>(server);
    }

protected:
    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Chat TCP server caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

int main(int argc, char** argv)
{
    // SSL server port
    int port = 2222;
    if (argc > 1)
        port = std::atoi(argv[1]);

    std::cout << "SSL server port: " << port << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create and prepare a new SSL server context
    auto context = std::make_shared<CppServer::Asio::SSLContext>(asio::ssl::context::tlsv12);
    context->set_password_callback([](size_t max_length, asio::ssl::context::password_purpose purpose) -> std::string { return "qwerty"; });
    context->use_certificate_chain_file("../tools/certificates/server.pem");
    context->use_private_key_file("../tools/certificates/server.pem", asio::ssl::context::pem);
    context->use_tmp_dh_file("../tools/certificates/dh4096.pem");

    // Create a new SSL chat server
    auto server = std::make_shared<ChatServer>(service, context, port);

    // Start the server
    std::cout << "Server starting...";
    server->Start();
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Restart the server
        if (line == "!")
        {
            std::cout << "Server restarting...";
            server->Restart();
            std::cout << "Done!" << std::endl;
            continue;
        }

        // Multicast admin message to all sessions
        line = "(admin) " + line;
        server->Multicast(line);
    }

    // Stop the server
    std::cout << "Server stopping...";
    server->Stop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: SSL chat client

Here comes the example of the SSL chat client. It connects to the SSL chat server and allows to send message to it and receive new messages.

This example is very similar to the TCP one except the code that prepares SSL context and handshake handler.

#include "server/asio/ssl_client.h"
#include "threads/thread.h"

#include <atomic>
#include <iostream>

class ChatClient : public CppServer::Asio::SSLClient
{
public:
    ChatClient(std::shared_ptr<CppServer::Asio::Service> service, std::shared_ptr<CppServer::Asio::SSLContext> context, const std::string& address, int port)
        : CppServer::Asio::SSLClient(service, context, address, port)
    {
        _stop = false;
    }

    void DisconnectAndStop()
    {
        _stop = true;
        DisconnectAsync();
        while (IsConnected())
            CppCommon::Thread::Yield();
    }

protected:
    void onConnected() override
    {
        std::cout << "Chat SSL client connected a new session with Id " << id() << std::endl;
    }

    void onHandshaked() override
    {
        std::cout << "Chat SSL client handshaked a new session with Id " << id() << std::endl;
    }

    void onDisconnected() override
    {
        std::cout << "Chat SSL client disconnected a session with Id " << id() << std::endl;

        // Wait for a while...
        CppCommon::Thread::Sleep(1000);

        // Try to connect again
        if (!_stop)
            ConnectAsync();
    }

    void onReceived(const void* buffer, size_t size) override
    {
        std::cout << "Incoming: " << std::string((const char*)buffer, size) << std::endl;
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Chat SSL client caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }

private:
    std::atomic<bool> _stop;
};

int main(int argc, char** argv)
{
    // SSL server address
    std::string address = "127.0.0.1";
    if (argc > 1)
        address = argv[1];

    // SSL server port
    int port = 2222;
    if (argc > 2)
        port = std::atoi(argv[2]);

    std::cout << "SSL server address: " << address << std::endl;
    std::cout << "SSL server port: " << port << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create and prepare a new SSL client context
    auto context = std::make_shared<CppServer::Asio::SSLContext>(asio::ssl::context::tlsv12);
    context->set_default_verify_paths();
    context->set_root_certs();
    context->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
    context->load_verify_file("../tools/certificates/ca.pem");

    // Create a new SSL chat client
    auto client = std::make_shared<ChatClient>(service, context, address, port);

    // Connect the client
    std::cout << "Client connecting...";
    client->ConnectAsync();
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Disconnect the client
        if (line == "!")
        {
            std::cout << "Client disconnecting...";
            client->DisconnectAsync();
            std::cout << "Done!" << std::endl;
            continue;
        }

        // Send the entered text to the chat server
        client->SendAsync(line);
    }

    // Disconnect the client
    std::cout << "Client disconnecting...";
    client->DisconnectAndStop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: UDP echo server

Here comes the example of the UDP echo server. It receives a datagram mesage from any UDP client and resend it back without any changes.

#include "server/asio/udp_server.h"
#include "threads/thread.h"

#include <iostream>

class EchoServer : public CppServer::Asio::UDPServer
{
public:
    using CppServer::Asio::UDPServer::UDPServer;

protected:
    void onStarted() override
    {
        // Start receive datagrams
        ReceiveAsync();
    }

    void onReceived(const asio::ip::udp::endpoint& endpoint, const void* buffer, size_t size) override
    {
        std::string message((const char*)buffer, size);
        std::cout << "Incoming: " << message << std::endl;

        // Echo the message back to the sender
        SendAsync(endpoint, message);
    }

    void onSent(const asio::ip::udp::endpoint& endpoint, size_t sent) override
    {
        // Continue receive datagrams
        ReceiveAsync();
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Echo UDP server caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

int main(int argc, char** argv)
{
    // UDP server port
    int port = 3333;
    if (argc > 1)
        port = std::atoi(argv[1]);

    std::cout << "UDP server port: " << port << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create a new UDP echo server
    auto server = std::make_shared<EchoServer>(service, port);

    // Start the server
    std::cout << "Server starting...";
    server->Start();
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Restart the server
        if (line == "!")
        {
            std::cout << "Server restarting...";
            server->Restart();
            std::cout << "Done!" << std::endl;
            continue;
        }
    }

    // Stop the server
    std::cout << "Server stopping...";
    server->Stop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: UDP echo client

Here comes the example of the UDP echo client. It sends user datagram message to UDP server and listen for response.

#include "server/asio/udp_client.h"
#include "threads/thread.h"

#include <atomic>
#include <iostream>

class EchoClient : public CppServer::Asio::UDPClient
{
public:
    EchoClient(std::shared_ptr<CppServer::Asio::Service> service, const std::string& address, int port)
        : CppServer::Asio::UDPClient(service, address, port)
    {
        _stop = false;
    }

    void DisconnectAndStop()
    {
        _stop = true;
        DisconnectAsync();
        while (IsConnected())
            CppCommon::Thread::Yield();
    }

protected:
    void onConnected() override
    {
        std::cout << "Echo UDP client connected a new session with Id " << id() << std::endl;

        // Start receive datagrams
        ReceiveAsync();
    }

    void onDisconnected() override
    {
        std::cout << "Echo UDP client disconnected a session with Id " << id() << std::endl;

        // Wait for a while...
        CppCommon::Thread::Sleep(1000);

        // Try to connect again
        if (!_stop)
            ConnectAsync();
    }

    void onReceived(const asio::ip::udp::endpoint& endpoint, const void* buffer, size_t size) override
    {
        std::cout << "Incoming: " << std::string((const char*)buffer, size) << std::endl;

        // Continue receive datagrams
        ReceiveAsync();
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Echo UDP client caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }

private:
    std::atomic<bool> _stop;
};

int main(int argc, char** argv)
{
    // UDP server address
    std::string address = "127.0.0.1";
    if (argc > 1)
        address = argv[1];

    // UDP server port
    int port = 3333;
    if (argc > 2)
        port = std::atoi(argv[2]);

    std::cout << "UDP server address: " << address << std::endl;
    std::cout << "UDP server port: " << port << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create a new UDP echo client
    auto client = std::make_shared<EchoClient>(service, address, port);

    // Connect the client
    std::cout << "Client connecting...";
    client->ConnectAsync();
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Disconnect the client
        if (line == "!")
        {
            std::cout << "Client disconnecting...";
            client->DisconnectAsync();
            std::cout << "Done!" << std::endl;
            continue;
        }

        // Send the entered text to the echo server
        client->SendSync(line);
    }

    // Disconnect the client
    std::cout << "Client disconnecting...";
    client->DisconnectAndStop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: UDP multicast server

Here comes the example of the UDP multicast server. It use multicast IP address to multicast datagram messages to all client that joined corresponding UDP multicast group.

#include "server/asio/udp_server.h"
#include "threads/thread.h"

#include <iostream>

class MulticastServer : public CppServer::Asio::UDPServer
{
public:
    using CppServer::Asio::UDPServer::UDPServer;

protected:
    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Multicast UDP server caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

int main(int argc, char** argv)
{
    // UDP multicast address
    std::string multicast_address = "239.255.0.1";
    if (argc > 1)
        multicast_address = argv[1];

    // UDP multicast port
    int multicast_port = 3334;
    if (argc > 2)
        multicast_port = std::atoi(argv[2]);

    std::cout << "UDP multicast address: " << multicast_address << std::endl;
    std::cout << "UDP multicast port: " << multicast_port << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create a new UDP multicast server
    auto server = std::make_shared<MulticastServer>(service, 0);

    // Start the multicast server
    std::cout << "Server starting...";
    server->Start(multicast_address, multicast_port);
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Restart the server
        if (line == "!")
        {
            std::cout << "Server restarting...";
            server->Restart();
            std::cout << "Done!" << std::endl;
            continue;
        }

        // Multicast admin message to all sessions
        line = "(admin) " + line;
        server->MulticastSync(line);
    }

    // Stop the server
    std::cout << "Server stopping...";
    server->Stop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: UDP multicast client

Here comes the example of the UDP multicast client. It use multicast IP address and joins UDP multicast group in order to receive multicasted datagram messages from UDP server.

#include "server/asio/udp_client.h"
#include "threads/thread.h"

#include <atomic>
#include <iostream>

class MulticastClient : public CppServer::Asio::UDPClient
{
public:
    MulticastClient(std::shared_ptr<CppServer::Asio::Service> service, const std::string& address, const std::string& multicast, int port)
        : CppServer::Asio::UDPClient(service, address, port),
          _multicast(multicast)
    {
        _stop = false;
    }

    void DisconnectAndStop()
    {
        _stop = true;
        DisconnectAsync();
        while (IsConnected())
            CppCommon::Thread::Yield();
    }

protected:
    void onConnected() override
    {
        std::cout << "Multicast UDP client connected a new session with Id " << id() << std::endl;

        // Join UDP multicast group
        JoinMulticastGroupAsync(_multicast);

        // Start receive datagrams
        ReceiveAsync();
    }

    void onDisconnected() override
    {
        std::cout << "Multicast UDP client disconnected a session with Id " << id() << std::endl;

        // Wait for a while...
        CppCommon::Thread::Sleep(1000);

        // Try to connect again
        if (!_stop)
            ConnectAsync();
    }

    void onReceived(const asio::ip::udp::endpoint& endpoint, const void* buffer, size_t size) override
    {
        std::cout << "Incoming: " << std::string((const char*)buffer, size) << std::endl;

        // Continue receive datagrams
        ReceiveAsync();
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Multicast UDP client caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }

private:
    std::atomic<bool> _stop;
    std::string _multicast;
};

int main(int argc, char** argv)
{
    // UDP listen address
    std::string listen_address = "0.0.0.0";
    if (argc > 1)
        listen_address = argv[1];

    // UDP multicast address
    std::string multicast_address = "239.255.0.1";
    if (argc > 2)
        multicast_address = argv[2];

    // UDP multicast port
    int multicast_port = 3334;
    if (argc > 3)
        multicast_port = std::atoi(argv[3]);

    std::cout << "UDP listen address: " << listen_address << std::endl;
    std::cout << "UDP multicast address: " << multicast_address << std::endl;
    std::cout << "UDP multicast port: " << multicast_port << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create a new UDP multicast client
    auto client = std::make_shared<MulticastClient>(service, listen_address, multicast_address, multicast_port);
    client->SetupMulticast(true);

    // Connect the client
    std::cout << "Client connecting...";
    client->ConnectAsync();
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Disconnect the client
        if (line == "!")
        {
            std::cout << "Client disconnecting...";
            client->DisconnectAsync();
            std::cout << "Done!" << std::endl;
            continue;
        }
    }

    // Disconnect the client
    std::cout << "Client disconnecting...";
    client->DisconnectAndStop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: HTTP server

Here comes the example of the HTTP cache server. It allows to manipulate cache data with HTTP methods (GET, POST, PUT and DELETE).

Use the following link to open Swagger OpenAPI iterative documentation: http://localhost:8080/api/index.html

OpenAPI-HTTP

#include "server/http/http_server.h"
#include "string/string_utils.h"
#include "utility/singleton.h"

#include <iostream>
#include <map>
#include <mutex>

class Cache : public CppCommon::Singleton<Cache>
{
   friend CppCommon::Singleton<Cache>;

public:
    std::string GetAllCache()
    {
        std::scoped_lock locker(_cache_lock);
        std::string result;
        result += "[\n";
        for (const auto& item : _cache)
        {
            result += "  {\n";
            result += "    \"key\": \"" + item.first + "\",\n";
            result += "    \"value\": \"" + item.second + "\",\n";
            result += "  },\n";
        }
        result += "]\n";
        return result;
    }

    bool GetCacheValue(std::string_view key, std::string& value)
    {
        std::scoped_lock locker(_cache_lock);
        auto it = _cache.find(key);
        if (it != _cache.end())
        {
            value = it->second;
            return true;
        }
        else
            return false;
    }

    void PutCacheValue(std::string_view key, std::string_view value)
    {
        std::scoped_lock locker(_cache_lock);
        auto it = _cache.emplace(key, value);
        if (!it.second)
            it.first->second = value;
    }

    bool DeleteCacheValue(std::string_view key, std::string& value)
    {
        std::scoped_lock locker(_cache_lock);
        auto it = _cache.find(key);
        if (it != _cache.end())
        {
            value = it->second;
            _cache.erase(it);
            return true;
        }
        else
            return false;
    }

private:
    std::mutex _cache_lock;
    std::map<std::string, std::string, std::less<>> _cache;
};

class HTTPCacheSession : public CppServer::HTTP::HTTPSession
{
public:
    using CppServer::HTTP::HTTPSession::HTTPSession;

protected:
    void onReceivedRequest(const CppServer::HTTP::HTTPRequest& request) override
    {
        // Show HTTP request content
        std::cout << std::endl << request;

        // Process HTTP request methods
        if (request.method() == "HEAD")
            SendResponseAsync(response().MakeHeadResponse());
        else if (request.method() == "GET")
        {
            std::string key(request.url());
            std::string value;

            // Decode the key value
            key = CppCommon::Encoding::URLDecode(key);
            CppCommon::StringUtils::ReplaceFirst(key, "/api/cache", "");
            CppCommon::StringUtils::ReplaceFirst(key, "?key=", "");

            if (key.empty())
            {
                // Response with all cache values
                SendResponseAsync(response().MakeGetResponse(Cache::GetInstance().GetAllCache(), "application/json; charset=UTF-8"));
            }
            // Get the cache value by the given key
            else if (Cache::GetInstance().GetCacheValue(key, value))
            {
                // Response with the cache value
                SendResponseAsync(response().MakeGetResponse(value));
            }
            else
                SendResponseAsync(response().MakeErrorResponse("Required cache value was not found for the key: " + key, 404));
        }
        else if ((request.method() == "POST") || (request.method() == "PUT"))
        {
            std::string key(request.url());
            std::string value(request.body());

            // Decode the key value
            key = CppCommon::Encoding::URLDecode(key);
            CppCommon::StringUtils::ReplaceFirst(key, "/api/cache", "");
            CppCommon::StringUtils::ReplaceFirst(key, "?key=", "");

            // Put the cache value
            Cache::GetInstance().PutCacheValue(key, value);

            // Response with the cache value
            SendResponseAsync(response().MakeOKResponse());
        }
        else if (request.method() == "DELETE")
        {
            std::string key(request.url());
            std::string value;

            // Decode the key value
            key = CppCommon::Encoding::URLDecode(key);
            CppCommon::StringUtils::ReplaceFirst(key, "/api/cache", "");
            CppCommon::StringUtils::ReplaceFirst(key, "?key=", "");

            // Delete the cache value
            if (Cache::GetInstance().DeleteCacheValue(key, value))
            {
                // Response with the cache value
                SendResponseAsync(response().MakeGetResponse(value));
            }
            else
                SendResponseAsync(response().MakeErrorResponse("Deleted cache value was not found for the key: " + key, 404));
        }
        else if (request.method() == "OPTIONS")
            SendResponseAsync(response().MakeOptionsResponse());
        else if (request.method() == "TRACE")
            SendResponseAsync(response().MakeTraceResponse(request.cache()));
        else
            SendResponseAsync(response().MakeErrorResponse("Unsupported HTTP method: " + std::string(request.method())));
    }

    void onReceivedRequestError(const CppServer::HTTP::HTTPRequest& request, const std::string& error) override
    {
        std::cout << "Request error: " << error << std::endl;
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "HTTP session caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

class HTTPCacheServer : public CppServer::HTTP::HTTPServer
{
public:
    using CppServer::HTTP::HTTPServer::HTTPServer;

protected:
    std::shared_ptr<CppServer::Asio::TCPSession> CreateSession(const std::shared_ptr<CppServer::Asio::TCPServer>& server) override
    {
        return std::make_shared<HTTPCacheSession>(std::dynamic_pointer_cast<CppServer::HTTP::HTTPServer>(server));
    }

protected:
    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "HTTP server caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

int main(int argc, char** argv)
{
    // HTTP server port
    int port = 8080;
    if (argc > 1)
        port = std::atoi(argv[1]);
    // HTTP server content path
    std::string www = "../www/api";
    if (argc > 2)
        www = argv[2];

    std::cout << "HTTP server port: " << port << std::endl;
    std::cout << "HTTP server static content path: " << www << std::endl;
    std::cout << "HTTP server website: " << "http://localhost:" << port << "/api/index.html" << std::endl;

    std::cout << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create a new HTTP server
    auto server = std::make_shared<HTTPCacheServer>(service, port);
    server->AddStaticContent(www, "/api");

    // Start the server
    std::cout << "Server starting...";
    server->Start();
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Restart the server
        if (line == "!")
        {
            std::cout << "Server restarting...";
            server->Restart();
            std::cout << "Done!" << std::endl;
            continue;
        }
    }

    // Stop the server
    std::cout << "Server stopping...";
    server->Stop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: HTTP client

Here comes the example of the HTTP client. It allows to send HTTP requests (GET, POST, PUT and DELETE) and receive HTTP responses.

#include "server/http/http_client.h"
#include "string/string_utils.h"

#include <iostream>

int main(int argc, char** argv)
{
    // HTTP server address
    std::string address = "127.0.0.1";
    if (argc > 1)
        address = argv[1];

    std::cout << "HTTP server address: " << address << std::endl;

    std::cout << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create a new HTTP client
    auto client = std::make_shared<CppServer::HTTP::HTTPClientEx>(service, address, "http");

    std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl;

    try
    {
        // Perform text input
        std::string line;
        while (getline(std::cin, line))
        {
            if (line.empty())
                break;

            // Reconnect the client
            if (line == "!")
            {
                std::cout << "Client reconnecting...";
                client->ReconnectAsync();
                std::cout << "Done!" << std::endl;
                continue;
            }

            auto commands = CppCommon::StringUtils::Split(line, ' ', true);
            if (commands.size() < 2)
            {
                std::cout << "HTTP method and URL must be entered!" << std::endl;
                continue;
            }

            if (CppCommon::StringUtils::ToUpper(commands[0]) == "HEAD")
            {
                auto response = client->SendHeadRequest(commands[1]).get();
                std::cout << response << std::endl;
            }
            else if (CppCommon::StringUtils::ToUpper(commands[0]) == "GET")
            {
                auto response = client->SendGetRequest(commands[1]).get();
                std::cout << response << std::endl;
            }
            else if (CppCommon::StringUtils::ToUpper(commands[0]) == "POST")
            {
                if (commands.size() < 3)
                {
                    std::cout << "HTTP method, URL and body must be entered!" << std::endl;
                    continue;
                }
                auto response = client->SendPostRequest(commands[1], commands[2]).get();
                std::cout << response << std::endl;
            }
            else if (CppCommon::StringUtils::ToUpper(commands[0]) == "PUT")
            {
                if (commands.size() < 3)
                {
                    std::cout << "HTTP method, URL and body must be entered!" << std::endl;
                    continue;
                }
                auto response = client->SendPutRequest(commands[1], commands[2]).get();
                std::cout << response << std::endl;
            }
            else if (CppCommon::StringUtils::ToUpper(commands[0]) == "DELETE")
            {
                auto response = client->SendDeleteRequest(commands[1]).get();
                std::cout << response << std::endl;
            }
            else if (CppCommon::StringUtils::ToUpper(commands[0]) == "OPTIONS")
            {
                auto response = client->SendOptionsRequest(commands[1]).get();
                std::cout << response << std::endl;
            }
            else if (CppCommon::StringUtils::ToUpper(commands[0]) == "TRACE")
            {
                auto response = client->SendTraceRequest(commands[1]).get();
                std::cout << response << std::endl;
            }
            else
                std::cout << "Unknown HTTP method: " << commands[0] << std::endl;
        }
    }
    catch (const std::exception& ex)
    {
        std::cerr << ex.what() << std::endl;
    }

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: HTTPS server

Here comes the example of the HTTPS cache server. It allows to manipulate cache data with HTTP methods (GET, POST, PUT and DELETE) with secured transport protocol.

Use the following link to open Swagger OpenAPI iterative documentation: https://localhost:8443/api/index.html

OpenAPI-HTTPS

#include "server/http/https_server.h"
#include "string/string_utils.h"
#include "utility/singleton.h"

#include <iostream>
#include <map>
#include <mutex>

class Cache : public CppCommon::Singleton<Cache>
{
   friend CppCommon::Singleton<Cache>;

public:
    std::string GetAllCache()
    {
        std::scoped_lock locker(_cache_lock);
        std::string result;
        result += "[\n";
        for (const auto& item : _cache)
        {
            result += "  {\n";
            result += "    \"key\": \"" + item.first + "\",\n";
            result += "    \"value\": \"" + item.second + "\",\n";
            result += "  },\n";
        }
        result += "]\n";
        return result;
    }

    bool GetCacheValue(std::string_view key, std::string& value)
    {
        std::scoped_lock locker(_cache_lock);
        auto it = _cache.find(key);
        if (it != _cache.end())
        {
            value = it->second;
            return true;
        }
        else
            return false;
    }

    void PutCacheValue(std::string_view key, std::string_view value)
    {
        std::scoped_lock locker(_cache_lock);
        auto it = _cache.emplace(key, value);
        if (!it.second)
            it.first->second = value;
    }

    bool DeleteCacheValue(std::string_view key, std::string& value)
    {
        std::scoped_lock locker(_cache_lock);
        auto it = _cache.find(key);
        if (it != _cache.end())
        {
            value = it->second;
            _cache.erase(it);
            return true;
        }
        else
            return false;
    }

private:
    std::mutex _cache_lock;
    std::map<std::string, std::string, std::less<>> _cache;
};

class HTTPSCacheSession : public CppServer::HTTP::HTTPSSession
{
public:
    using CppServer::HTTP::HTTPSSession::HTTPSSession;

protected:
    void onReceivedRequest(const CppServer::HTTP::HTTPRequest& request) override
    {
        // Show HTTP request content
        std::cout << std::endl << request;

        // Process HTTP request methods
        if (request.method() == "HEAD")
            SendResponseAsync(response().MakeHeadResponse());
        else if (request.method() == "GET")
        {
            std::string key(request.url());
            std::string value;

            // Decode the key value
            key = CppCommon::Encoding::URLDecode(key);
            CppCommon::StringUtils::ReplaceFirst(key, "/api/cache", "");
            CppCommon::StringUtils::ReplaceFirst(key, "?key=", "");

            if (key.empty())
            {
                // Response with all cache values
                SendResponseAsync(response().MakeGetResponse(Cache::GetInstance().GetAllCache(), "application/json; charset=UTF-8"));
            }
            // Get the cache value by the given key
            else if (Cache::GetInstance().GetCacheValue(key, value))
            {
                // Response with the cache value
                SendResponseAsync(response().MakeGetResponse(value));
            }
            else
                SendResponseAsync(response().MakeErrorResponse("Required cache value was not found for the key: " + key, 404));
        }
        else if ((request.method() == "POST") || (request.method() == "PUT"))
        {
            std::string key(request.url());
            std::string value(request.body());

            // Decode the key value
            key = CppCommon::Encoding::URLDecode(key);
            CppCommon::StringUtils::ReplaceFirst(key, "/api/cache", "");
            CppCommon::StringUtils::ReplaceFirst(key, "?key=", "");

            // Put the cache value
            Cache::GetInstance().PutCacheValue(key, value);

            // Response with the cache value
            SendResponseAsync(response().MakeOKResponse());
        }
        else if (request.method() == "DELETE")
        {
            std::string key(request.url());
            std::string value;

            // Decode the key value
            key = CppCommon::Encoding::URLDecode(key);
            CppCommon::StringUtils::ReplaceFirst(key, "/api/cache", "");
            CppCommon::StringUtils::ReplaceFirst(key, "?key=", "");

            // Delete the cache value
            if (Cache::GetInstance().DeleteCacheValue(key, value))
            {
                // Response with the cache value
                SendResponseAsync(response().MakeGetResponse(value));
            }
            else
                SendResponseAsync(response().MakeErrorResponse("Deleted cache value was not found for the key: " + key, 404));
        }
        else if (request.method() == "OPTIONS")
            SendResponseAsync(response().MakeOptionsResponse());
        else if (request.method() == "TRACE")
            SendResponseAsync(response().MakeTraceResponse(request.cache()));
        else
            SendResponseAsync(response().MakeErrorResponse("Unsupported HTTP method: " + std::string(request.method())));
    }

    void onReceivedRequestError(const CppServer::HTTP::HTTPRequest& request, const std::string& error) override
    {
        std::cout << "Request error: " << error << std::endl;
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "HTTPS session caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

class HTTPSCacheServer : public CppServer::HTTP::HTTPSServer
{
public:
    using CppServer::HTTP::HTTPSServer::HTTPSServer;

protected:
    std::shared_ptr<CppServer::Asio::SSLSession> CreateSession(const std::shared_ptr<CppServer::Asio::SSLServer>& server) override
    {
        return std::make_shared<HTTPSCacheSession>(std::dynamic_pointer_cast<CppServer::HTTP::HTTPSServer>(server));
    }

protected:
    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "HTTPS server caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

int main(int argc, char** argv)
{
    // HTTPS server port
    int port = 8443;
    if (argc > 1)
        port = std::atoi(argv[1]);
    // HTTPS server content path
    std::string www = "../www/api";
    if (argc > 2)
        www = argv[2];

    std::cout << "HTTPS server port: " << port << std::endl;
    std::cout << "HTTPS server static content path: " << www << std::endl;
    std::cout << "HTTPS server website: " << "https://localhost:" << port << "/api/index.html" << std::endl;

    std::cout << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create and prepare a new SSL server context
    auto context = std::make_shared<CppServer::Asio::SSLContext>(asio::ssl::context::tlsv12);
    context->set_password_callback([](size_t max_length, asio::ssl::context::password_purpose purpose) -> std::string { return "qwerty"; });
    context->use_certificate_chain_file("../tools/certificates/server.pem");
    context->use_private_key_file("../tools/certificates/server.pem", asio::ssl::context::pem);
    context->use_tmp_dh_file("../tools/certificates/dh4096.pem");

    // Create a new HTTPS server
    auto server = std::make_shared<HTTPSCacheServer>(service, context, port);
    server->AddStaticContent(www, "/api");

    // Start the server
    std::cout << "Server starting...";
    server->Start();
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Restart the server
        if (line == "!")
        {
            std::cout << "Server restarting...";
            server->Restart();
            std::cout << "Done!" << std::endl;
            continue;
        }
    }

    // Stop the server
    std::cout << "Server stopping...";
    server->Stop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: HTTPS client

Here comes the example of the HTTPS client. It allows to send HTTP requests (GET, POST, PUT and DELETE) and receive HTTP responses with secured transport protocol.

#include "server/http/https_client.h"
#include "string/string_utils.h"

#include <iostream>

int main(int argc, char** argv)
{
    // HTTP server address
    std::string address = "127.0.0.1";
    if (argc > 1)
        address = argv[1];

    std::cout << "HTTPS server address: " << address << std::endl;

    std::cout << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create and prepare a new SSL client context
    auto context = std::make_shared<CppServer::Asio::SSLContext>(asio::ssl::context::tlsv12);
    context->set_default_verify_paths();
    context->set_root_certs();
    context->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
    context->load_verify_file("../tools/certificates/ca.pem");

    // Create a new HTTP client
    auto client = std::make_shared<CppServer::HTTP::HTTPSClientEx>(service, context, address, "https");

    std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl;

    try
    {
        // Perform text input
        std::string line;
        while (getline(std::cin, line))
        {
            if (line.empty())
                break;

            // Reconnect the client
            if (line == "!")
            {
                std::cout << "Client reconnecting...";
                client->ReconnectAsync();
                std::cout << "Done!" << std::endl;
                continue;
            }

            auto commands = CppCommon::StringUtils::Split(line, ' ', true);
            if (commands.size() < 2)
            {
                std::cout << "HTTP method and URL must be entered!" << std::endl;
                continue;
            }

            if (CppCommon::StringUtils::ToUpper(commands[0]) == "HEAD")
            {
                auto response = client->SendHeadRequest(commands[1]).get();
                std::cout << response << std::endl;
            }
            else if (CppCommon::StringUtils::ToUpper(commands[0]) == "GET")
            {
                auto response = client->SendGetRequest(commands[1]).get();
                std::cout << response << std::endl;
            }
            else if (CppCommon::StringUtils::ToUpper(commands[0]) == "POST")
            {
                if (commands.size() < 3)
                {
                    std::cout << "HTTP method, URL and body must be entered!" << std::endl;
                    continue;
                }
                auto response = client->SendPostRequest(commands[1], commands[2]).get();
                std::cout << response << std::endl;
            }
            else if (CppCommon::StringUtils::ToUpper(commands[0]) == "PUT")
            {
                if (commands.size() < 3)
                {
                    std::cout << "HTTP method, URL and body must be entered!" << std::endl;
                    continue;
                }
                auto response = client->SendPutRequest(commands[1], commands[2]).get();
                std::cout << response << std::endl;
            }
            else if (CppCommon::StringUtils::ToUpper(commands[0]) == "DELETE")
            {
                auto response = client->SendDeleteRequest(commands[1]).get();
                std::cout << response << std::endl;
            }
            else if (CppCommon::StringUtils::ToUpper(commands[0]) == "OPTIONS")
            {
                auto response = client->SendOptionsRequest(commands[1]).get();
                std::cout << response << std::endl;
            }
            else if (CppCommon::StringUtils::ToUpper(commands[0]) == "TRACE")
            {
                auto response = client->SendTraceRequest(commands[1]).get();
                std::cout << response << std::endl;
            }
            else
                std::cout << "Unknown HTTP method: " << commands[0] << std::endl;
        }
    }
    catch (const std::exception& ex)
    {
        std::cerr << ex.what() << std::endl;
    }

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: WebSocket chat server

Here comes the example of the WebSocket chat server. It handles multiple WebSocket client sessions and multicast received message from any session to all ones. Also it is possible to send admin message directly from the server.

Use the following link to open WebSocket chat server example: http://localhost:8080/chat/index.html

ws-chat

#include "server/ws/ws_server.h"

#include <iostream>

class ChatSession : public CppServer::WS::WSSession
{
public:
    using CppServer::WS::WSSession::WSSession;

protected:
    void onWSConnected(const CppServer::HTTP::HTTPRequest& request) override
    {
        std::cout << "Chat WebSocket session with Id " << id() << " connected!" << std::endl;

        // Send invite message
        std::string message("Hello from WebSocket chat! Please send a message or '!' to disconnect the client!");
        SendTextAsync(message);
    }

    void onWSDisconnected() override
    {
        std::cout << "Chat WebSocket session with Id " << id() << " disconnected!" << std::endl;
    }

    void onWSReceived(const void* buffer, size_t size) override
    {
        std::string message((const char*)buffer, size);
        std::cout << "Incoming: " << message << std::endl;

        // Multicast message to all connected sessions
        std::dynamic_pointer_cast<CppServer::WS::WSServer>(server())->MulticastText(message);

        // If the buffer starts with '!' the disconnect the current session
        if (message == "!")
            Close(1000);
    }

    void onWSPing(const void* buffer, size_t size) override
    {
        SendPongAsync(buffer, size);
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Chat WebSocket session caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

class ChatServer : public CppServer::WS::WSServer
{
public:
    using CppServer::WS::WSServer::WSServer;

protected:
    std::shared_ptr<CppServer::Asio::TCPSession> CreateSession(std::shared_ptr<CppServer::Asio::TCPServer> server) override
    {
        return std::make_shared<ChatSession>(std::dynamic_pointer_cast<CppServer::WS::WSServer>(server));
    }

protected:
    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Chat WebSocket server caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

int main(int argc, char** argv)
{
    // WebSocket server port
    int port = 8080;
    if (argc > 1)
        port = std::atoi(argv[1]);
    // WebSocket server content path
    std::string www = "../www/ws";
    if (argc > 2)
        www = argv[2];

    std::cout << "WebSocket server port: " << port << std::endl;
    std::cout << "WebSocket server static content path: " << www << std::endl;
    std::cout << "WebSocket server website: " << "http://localhost:" << port << "/chat/index.html" << std::endl;

    std::cout << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create a new WebSocket chat server
    auto server = std::make_shared<ChatServer>(service, port);
    server->AddStaticContent(www, "/chat");

    // Start the server
    std::cout << "Server starting...";
    server->Start();
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Restart the server
        if (line == "!")
        {
            std::cout << "Server restarting...";
            server->Restart();
            std::cout << "Done!" << std::endl;
            continue;
        }

        // Multicast admin message to all sessions
        line = "(admin) " + line;
        server->MulticastText(line);
    }

    // Stop the server
    std::cout << "Server stopping...";
    server->Stop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: WebSocket chat client

Here comes the example of the WebSocket chat client. It connects to the WebSocket chat server and allows to send message to it and receive new messages.

#include "server/ws/ws_client.h"
#include "threads/thread.h"

#include <atomic>
#include <iostream>

class ChatClient : public CppServer::WS::WSClient
{
public:
    using CppServer::WS::WSClient::WSClient;

    void DisconnectAndStop()
    {
        _stop = true;
        CloseAsync(1000);
        while (IsConnected())
            CppCommon::Thread::Yield();
    }

protected:
    void onWSConnecting(CppServer::HTTP::HTTPRequest& request) override
    {
        request.SetBegin("GET", "/");
        request.SetHeader("Host", "localhost");
        request.SetHeader("Origin", "http://localhost");
        request.SetHeader("Upgrade", "websocket");
        request.SetHeader("Connection", "Upgrade");
        request.SetHeader("Sec-WebSocket-Key", CppCommon::Encoding::Base64Encode(ws_nonce()));
        request.SetHeader("Sec-WebSocket-Protocol", "chat, superchat");
        request.SetHeader("Sec-WebSocket-Version", "13");
    }

    void onWSConnected(const CppServer::HTTP::HTTPResponse& response) override
    {
        std::cout << "Chat WebSocket client connected a new session with Id " << id() << std::endl;
    }

    void onWSDisconnected() override
    {
        std::cout << "Chat WebSocket client disconnected a session with Id " << id() << std::endl;
    }

    void onWSReceived(const void* buffer, size_t size) override
    {
        std::cout << "Incoming: " << std::string((const char*)buffer, size) << std::endl;
    }

    void onWSPing(const void* buffer, size_t size) override
    {
        SendPongAsync(buffer, size);
    }

    void onDisconnected() override
    {
        WSClient::onDisconnected();

        // Wait for a while...
        CppCommon::Thread::Sleep(1000);

        // Try to connect again
        if (!_stop)
            ConnectAsync();
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Chat WebSocket client caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }

private:
    std::atomic<bool> _stop{false};
};

int main(int argc, char** argv)
{
    // WebSocket server address
    std::string address = "127.0.0.1";
    if (argc > 1)
        address = argv[1];

    // WebSocket server port
    int port = 8080;
    if (argc > 2)
        port = std::atoi(argv[2]);

    std::cout << "WebSocket server address: " << address << std::endl;
    std::cout << "WebSocket server port: " << port << std::endl;

    std::cout << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create a new WebSocket chat client
    auto client = std::make_shared<ChatClient>(service, address, port);

    // Connect the client
    std::cout << "Client connecting...";
    client->ConnectAsync();
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Reconnect the client
        if (line == "!")
        {
            std::cout << "Client reconnecting...";
            client->ReconnectAsync();
            std::cout << "Done!" << std::endl;
            continue;
        }

        // Send the entered text to the chat server
        client->SendTextAsync(line);
    }

    // Disconnect the client
    std::cout << "Client disconnecting...";
    client->DisconnectAndStop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: WebSocket secure chat server

Here comes the example of the WebSocket secure chat server. It handles multiple WebSocket secure client sessions and multicast received message from any session to all ones. Also it is possible to send admin message directly from the server.

This example is very similar to the WebSocket one except the code that prepares WebSocket secure context and handshake handler.

Use the following link to open WebSocket secure chat server example: https://localhost:8443/chat/index.html

wss-chat

#include "server/ws/wss_server.h"

#include <iostream>

class ChatSession : public CppServer::WS::WSSSession
{
public:
    using CppServer::WS::WSSSession::WSSSession;

protected:
    void onWSConnected(const CppServer::HTTP::HTTPRequest& request) override
    {
        std::cout << "Chat WebSocket secure session with Id " << id() << " connected!" << std::endl;

        // Send invite message
        std::string message("Hello from WebSocket secure chat! Please send a message or '!' to disconnect the client!");
        SendTextAsync(message);
    }

    void onWSDisconnected() override
    {
        std::cout << "Chat WebSocket secure session with Id " << id() << " disconnected!" << std::endl;
    }

    void onWSReceived(const void* buffer, size_t size) override
    {
        std::string message((const char*)buffer, size);
        std::cout << "Incoming: " << message << std::endl;

        // Multicast message to all connected sessions
        std::dynamic_pointer_cast<CppServer::WS::WSSServer>(server())->MulticastText(message);

        // If the buffer starts with '!' the disconnect the current session
        if (message == "!")
            Close(1000);
    }

    void onWSPing(const void* buffer, size_t size) override
    {
        SendPongAsync(buffer, size);
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Chat WebSocket secure session caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

class ChatServer : public CppServer::WS::WSSServer
{
public:
    using CppServer::WS::WSSServer::WSSServer;

protected:
    std::shared_ptr<CppServer::Asio::SSLSession> CreateSession(std::shared_ptr<CppServer::Asio::SSLServer> server) override
    {
        return std::make_shared<ChatSession>(std::dynamic_pointer_cast<CppServer::WS::WSSServer>(server));
    }

protected:
    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Chat WebSocket secure server caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }
};

int main(int argc, char** argv)
{
    // WebSocket secure server port
    int port = 8443;
    if (argc > 1)
        port = std::atoi(argv[1]);
    // WebSocket secure server content path
    std::string www = "../www/wss";
    if (argc > 2)
        www = argv[2];

    std::cout << "WebSocket secure server port: " << port << std::endl;
    std::cout << "WebSocket secure server static content path: " << www << std::endl;
    std::cout << "WebSocket server website: " << "https://localhost:" << port << "/chat/index.html" << std::endl;

    std::cout << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create and prepare a new SSL server context
    auto context = std::make_shared<CppServer::Asio::SSLContext>(asio::ssl::context::tlsv12);
    context->set_password_callback([](size_t max_length, asio::ssl::context::password_purpose purpose) -> std::string { return "qwerty"; });
    context->use_certificate_chain_file("../tools/certificates/server.pem");
    context->use_private_key_file("../tools/certificates/server.pem", asio::ssl::context::pem);
    context->use_tmp_dh_file("../tools/certificates/dh4096.pem");

    // Create a new WebSocket secure chat server
    auto server = std::make_shared<ChatServer>(service, context, port);
    server->AddStaticContent(www, "/chat");

    // Start the server
    std::cout << "Server starting...";
    server->Start();
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the server or '!' to restart the server..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Restart the server
        if (line == "!")
        {
            std::cout << "Server restarting...";
            server->Restart();
            std::cout << "Done!" << std::endl;
            continue;
        }

        // Multicast admin message to all sessions
        line = "(admin) " + line;
        server->MulticastText(line);
    }

    // Stop the server
    std::cout << "Server stopping...";
    server->Stop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Example: WebSocket secure chat client

Here comes the example of the WebSocket secure chat client. It connects to the WebSocket secure chat server and allows to send message to it and receive new messages.

This example is very similar to the WebSocket one except the code that prepares WebSocket secure context and handshake handler.

#include "server/ws/wss_client.h"
#include "threads/thread.h"

#include <atomic>
#include <iostream>

class ChatClient : public CppServer::WS::WSSClient
{
public:
    using CppServer::WS::WSSClient::WSSClient;

    void DisconnectAndStop()
    {
        _stop = true;
        CloseAsync(1000);
        while (IsConnected())
            CppCommon::Thread::Yield();
    }

protected:
    void onWSConnecting(CppServer::HTTP::HTTPRequest& request) override
    {
        request.SetBegin("GET", "/");
        request.SetHeader("Host", "localhost");
        request.SetHeader("Origin", "https://localhost");
        request.SetHeader("Upgrade", "websocket");
        request.SetHeader("Connection", "Upgrade");
        request.SetHeader("Sec-WebSocket-Key", CppCommon::Encoding::Base64Encode(ws_nonce()));
        request.SetHeader("Sec-WebSocket-Protocol", "chat, superchat");
        request.SetHeader("Sec-WebSocket-Version", "13");
    }

    void onWSConnected(const CppServer::HTTP::HTTPResponse& response) override
    {
        std::cout << "Chat WebSocket secure client connected a new session with Id " << id() << std::endl;
    }

    void onWSDisconnected() override
    {
        std::cout << "Chat WebSocket secure client disconnected a session with Id " << id() << std::endl;
    }

    void onWSReceived(const void* buffer, size_t size) override
    {
        std::cout << "Incoming: " << std::string((const char*)buffer, size) << std::endl;
    }

    void onWSPing(const void* buffer, size_t size) override
    {
        SendPongAsync(buffer, size);
    }

    void onDisconnected() override
    {
        WSSClient::onDisconnected();

        // Wait for a while...
        CppCommon::Thread::Sleep(1000);

        // Try to connect again
        if (!_stop)
            ConnectAsync();
    }

    void onError(int error, const std::string& category, const std::string& message) override
    {
        std::cout << "Chat WebSocket secure client caught an error with code " << error << " and category '" << category << "': " << message << std::endl;
    }

private:
    std::atomic<bool> _stop{false};
};

int main(int argc, char** argv)
{
    // WebSocket server address
    std::string address = "127.0.0.1";
    if (argc > 1)
        address = argv[1];

    // WebSocket server port
    int port = 8443;
    if (argc > 2)
        port = std::atoi(argv[2]);

    std::cout << "WebSocket secure server address: " << address << std::endl;
    std::cout << "WebSocket secure server port: " << port << std::endl;

    std::cout << std::endl;

    // Create a new Asio service
    auto service = std::make_shared<CppServer::Asio::Service>();

    // Start the Asio service
    std::cout << "Asio service starting...";
    service->Start();
    std::cout << "Done!" << std::endl;

    // Create and prepare a new SSL client context
    auto context = std::make_shared<CppServer::Asio::SSLContext>(asio::ssl::context::tlsv12);
    context->set_default_verify_paths();
    context->set_root_certs();
    context->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
    context->load_verify_file("../tools/certificates/ca.pem");

    // Create a new WebSocket chat client
    auto client = std::make_shared<ChatClient>(service, context, address, port);

    // Connect the client
    std::cout << "Client connecting...";
    client->ConnectAsync();
    std::cout << "Done!" << std::endl;

    std::cout << "Press Enter to stop the client or '!' to reconnect the client..." << std::endl;

    // Perform text input
    std::string line;
    while (getline(std::cin, line))
    {
        if (line.empty())
            break;

        // Reconnect the client
        if (line == "!")
        {
            std::cout << "Client reconnecting...";
            client->ReconnectAsync();
            std::cout << "Done!" << std::endl;
            continue;
        }

        // Send the entered text to the chat server
        client->SendTextAsync(line);
    }

    // Disconnect the client
    std::cout << "Client disconnecting...";
    client->DisconnectAndStop();
    std::cout << "Done!" << std::endl;

    // Stop the Asio service
    std::cout << "Asio service stopping...";
    service->Stop();
    std::cout << "Done!" << std::endl;

    return 0;
}

Performance

Here comes several communication scenarios with timing measurements.

Benchmark environment is the following:

CPU architecutre: Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz
CPU logical cores: 8
CPU physical cores: 4
CPU clock speed: 3.998 GHz
CPU Hyper-Threading: enabled
RAM total: 31.962 GiB
RAM free: 21.623 GiB

OS version: Microsoft Windows 8 Enterprise Edition (build 9200), 64-bit
OS bits: 64-bit
Process bits: 64-bit
Process configuaraion: release

Benchmark: Round-Trip

Round-trip

This scenario sends lots of messages from several clients to a server. The server responses to each message and resend the similar response to the client. The benchmark measures total round-trip time to send all messages and receive all responses, messages & data throughput, count of errors.

TCP echo server

Server address: 127.0.0.1
Server port: 1111
Working threads: 1
Working clients: 1
Working messages: 1000
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.001 s
Total data: 1.692 GiB
Total messages: 56261685
Data throughput: 171.693 MiB/s
Message latency: 177 ns
Message throughput: 5625528 msg/s
Server address: 127.0.0.1
Server port: 1111
Working threads: 4
Working clients: 100
Working messages: 1000
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.007 s
Total data: 1.151 GiB
Total messages: 38503396
Data throughput: 117.423 MiB/s
Message latency: 259 ns
Message throughput: 3847402 msg/s

SSL echo server

Server address: 127.0.0.1
Server port: 2222
Working threads: 1
Working clients: 1
Working messages: 1000
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.012 s
Total data: 296.350 MiB
Total messages: 9710535
Data throughput: 29.612 MiB/s
Message latency: 1.031 mcs
Message throughput: 969878 msg/s
Server address: 127.0.0.1
Server port: 2222
Working threads: 4
Working clients: 100
Working messages: 1000
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.341 s
Total data: 390.660 MiB
Total messages: 12800660
Data throughput: 37.792 MiB/s
Message latency: 807 ns
Message throughput: 1237782 msg/s

UDP echo server

Server address: 127.0.0.1
Server port: 3333
Working threads: 1
Working clients: 1
Working messages: 1000
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.002 s
Total data: 46.032 MiB
Total messages: 1508355
Data throughput: 4.616 MiB/s
Message latency: 6.631 mcs
Message throughput: 150801 msg/s
Server address: 127.0.0.1
Server port: 3333
Working threads: 4
Working clients: 100
Working messages: 1000
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.152 s
Total data: 32.185 MiB
Total messages: 1054512
Data throughput: 3.173 MiB/s
Message latency: 9.627 mcs
Message throughput: 103867 msg/s

WebSocket echo server

Server address: 127.0.0.1
Server port: 8080
Working threads: 1
Working clients: 1
Working messages: 1000
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 9.994 s
Total data: 48.958 MiB
Total messages: 1603548
Data throughput: 4.918 MiB/s
Message latency: 6.232 mcs
Message throughput: 160448 msg/s
Server address: 127.0.0.1
Server port: 8080
Working threads: 4
Working clients: 100
Working messages: 1000
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 11.402 s
Total data: 206.827 MiB
Total messages: 6776702
Data throughput: 18.140 MiB/s
Message latency: 1.682 mcs
Message throughput: 594328 msg/s

WebSocket secure echo server

Server address: 127.0.0.1
Server port: 8443
Working threads: 1
Working clients: 1
Working messages: 1000
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.001 s
Total data: 62.068 MiB
Total messages: 2033811
Data throughput: 6.210 MiB/s
Message latency: 4.917 mcs
Message throughput: 203343 msg/s
Server address: 127.0.0.1
Server port: 8443
Working threads: 4
Working clients: 100
Working messages: 1000
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.011 s
Total data: 249.1023 MiB
Total messages: 8191971
Data throughput: 24.993 MiB/s
Message latency: 1.222 mcs
Message throughput: 818230 msg/s

Benchmark: Multicast

Multicast

In this scenario server multicasts messages to all connected clients. The benchmark counts total messages received by all clients for all the working time and measures messages & data throughput, count of errors.

TCP multicast server

Server address: 127.0.0.1
Server port: 1111
Working threads: 1
Working clients: 1
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.001 s
Total data: 1.907 GiB
Total messages: 63283367
Data throughput: 193.103 MiB/s
Message latency: 158 ns
Message throughput: 6327549 msg/s
Server address: 127.0.0.1
Server port: 1111
Working threads: 4
Working clients: 100
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.006 s
Total data: 1.1006 GiB
Total messages: 66535013
Data throughput: 202.930 MiB/s
Message latency: 150 ns
Message throughput: 6648899 msg/s

SSL multicast server

Server address: 127.0.0.1
Server port: 2222
Working threads: 1
Working clients: 1
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.014 s
Total data: 1.535 GiB
Total messages: 51100073
Data throughput: 155.738 MiB/s
Message latency: 195 ns
Message throughput: 5102683 msg/s
Server address: 127.0.0.1
Server port: 2222
Working threads: 4
Working clients: 100
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.691 s
Total data: 1.878 GiB
Total messages: 62334478
Data throughput: 177.954 MiB/s
Message latency: 171 ns
Message throughput: 5830473 msg/s

UDP multicast server

Server address: 239.255.0.1
Server port: 3333
Working threads: 1
Working clients: 1
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.002 s
Total data: 23.777 MiB
Total messages: 778555
Data throughput: 2.384 MiB/s
Message latency: 12.847 mcs
Message throughput: 77833 msg/s
Server address: 239.255.0.1
Server port: 3333
Working threads: 4
Working clients: 100
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.004 s
Total data: 52.457 MiB
Total messages: 1718575
Data throughput: 5.248 MiB/s
Message latency: 5.821 mcs
Message throughput: 171784 msg/s

WebSocket multicast server

Server address: 127.0.0.1
Server port: 8080
Working threads: 1
Working clients: 1
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.001 s
Total data: 960.902 MiB
Total messages: 31486166
Data throughput: 96.075 MiB/s
Message latency: 317 ns
Message throughput: 3148135 msg/s
Server address: 127.0.0.1
Server port: 8080
Working threads: 4
Working clients: 100
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.020 s
Total data: 986.489 MiB
Total messages: 32324898
Data throughput: 98.459 MiB/s
Message latency: 309 ns
Message throughput: 3225965 msg/s

WebSocket secure multicast server

Server address: 127.0.0.1
Server port: 8443
Working threads: 1
Working clients: 1
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.002 s
Total data: 1.041 GiB
Total messages: 34903186
Data throughput: 106.505 MiB/s
Message latency: 286 ns
Message throughput: 3489578 msg/s
Server address: 127.0.0.1
Server port: 8443
Working threads: 4
Working clients: 100
Message size: 32
Seconds to benchmarking: 10

Errors: 0

Total time: 10.013 s
Total data: 1.569 GiB
Total messages: 52225588
Data throughput: 159.172 MiB/s
Message latency: 191 ns
Message throughput: 5215639 msg/s

Benchmark: Web Server

HTTP Trace server

Server address: 127.0.0.1
Server port: 80
Working threads: 1
Working clients: 1
Working messages: 1
Seconds to benchmarking: 10

Errors: 0

Total time: 10.001 s
Total data: 58.476 MiB
Total messages: 578353
Data throughput: 5.865 MiB/s
Message latency: 17.293 mcs
Message throughput: 57825 msg/s
Server address: 127.0.0.1
Server port: 80
Working threads: 4
Working clients: 100
Working messages: 1
Seconds to benchmarking: 10

Errors: 0

Total time: 10.006 s
Total data: 310.730 MiB
Total messages: 3073650
Data throughput: 31.051 MiB/s
Message latency: 3.255 mcs
Message throughput: 307154 msg/s

HTTPS Trace server

Server address: 127.0.0.1
Server port: 443
Working threads: 1
Working clients: 1
Working messages: 1
Seconds to benchmarking: 10

Errors: 0

Total time: 10.003 s
Total data: 37.475 MiB
Total messages: 370602
Data throughput: 3.763 MiB/s
Message latency: 26.992 mcs
Message throughput: 37047 msg/s
Server address: 127.0.0.1
Server port: 443
Working threads: 4
Working clients: 100
Working messages: 1
Seconds to benchmarking: 10

Errors: 0

Total time: 10.035 s
Total data: 204.531 MiB
Total messages: 2023152
Data throughput: 20.389 MiB/s
Message latency: 4.960 mcs
Message throughput: 201602 msg/s

OpenSSL certificates

In order to create OpenSSL based server and client you should prepare a set of SSL certificates.

Production

Depending on your project, you may need to purchase a traditional SSL certificate signed by a Certificate Authority. If you, for instance, want some else's web browser to talk to your WebSocket project, you'll need a traditional SSL certificate.

Development

The commands below entered in the order they are listed will generate a self-signed certificate for development or testing purposes.

If you want to save some time, download and run Generate-Certs and it will generate the certs for you in less than a minute. Supports Windows + Linux.

If you'd rather enter in the commands to generate the certificates manually, here is the list in order below.

Certificate Authority

  • Create CA private key
openssl genrsa -passout pass:qwerty -out ca-secret.key 4096
  • Remove passphrase
openssl rsa -passin pass:qwerty -in ca-secret.key -out ca.key
  • Create CA self-signed certificate
openssl req -new -x509 -days 3650 -subj '/C=BY/ST=Belarus/L=Minsk/O=Example root CA/OU=Example CA unit/CN=example.com' -key ca.key -out ca.crt
  • Convert CA self-signed certificate to PFX
openssl pkcs12 -export -passout pass:qwerty -inkey ca.key -in ca.crt -out ca.pfx
  • Convert CA self-signed certificate to PEM
openssl pkcs12 -passin pass:qwerty -passout pass:qwerty -in ca.pfx -out ca.pem

SSL Server certificate

  • Create private key for the server
openssl genrsa -passout pass:qwerty -out server-secret.key 4096
  • Remove passphrase
openssl rsa -passin pass:qwerty -in server-secret.key -out server.key
  • Create CSR for the server
openssl req -new -subj '/C=BY/ST=Belarus/L=Minsk/O=Example server/OU=Example server unit/CN=server.example.com' -key server.key -out server.csr
  • Create certificate for the server
openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
  • Convert the server certificate to PFX
openssl pkcs12 -export -passout pass:qwerty -inkey server.key -in server.crt -out server.pfx
  • Convert the server certificate to PEM
openssl pkcs12 -passin pass:qwerty -passout pass:qwerty -in server.pfx -out server.pem

SSL Client certificate

  • Create private key for the client
openssl genrsa -passout pass:qwerty -out client-secret.key 4096
  • Remove passphrase
openssl rsa -passin pass:qwerty -in client-secret.key -out client.key
  • Create CSR for the client
openssl req -new -subj '/C=BY/ST=Belarus/L=Minsk/O=Example client/OU=Example client unit/CN=client.example.com' -key client.key -out client.csr
  • Create the client certificate
openssl x509 -req -days 3650 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
  • Convert the client certificate to PFX
openssl pkcs12 -export -passout pass:qwerty -inkey client.key -in client.crt -out client.pfx
  • Convert the client certificate to PEM
openssl pkcs12 -passin pass:qwerty -passout pass:qwerty -in client.pfx -out client.pem

Diffie-Hellman key exchange

  • Create DH parameters
openssl dhparam -out dh4096.pem 4096
Comments
  • error compiling library on windows 10 using Mingw32 7.3.0 comes with QT 5.13.2

    error compiling library on windows 10 using Mingw32 7.3.0 comes with QT 5.13.2

    Hi,

    I got this error when I tried to compile the library I follow the steps exactly, i use windows 10, compiler MinGW 32 7.3.0

    -- The System identification is Windows-10.0.17134 Windows 10.0.17134 Platform/Windows -- Could NOT find Crypt (missing: CRYPT_INCLUDE_DIR) -- Could NOT find WinSock (missing: WINSOCK_INCLUDE_DIR) -- The System identification is Windows-10.0.17134 Windows 10.0.17134 Platform/Windows -- The System identification is Windows-10.0.17134 Windows 10.0.17134 Platform/Windows -- Could NOT find DbgHelp (missing: DBGHELP_INCLUDE_DIR) -- Could NOT find RPC (missing: RPC_INCLUDE_DIR) -- Could NOT find Userenv (missing: USERENV_INCLUDE_DIR) -- OpenSSL version: 1.1.1d D:/cook/CppServer/CppServer/modules/OpenSSL/MinGW/include D:/cook/CppServer/CppServer/modules/OpenSSL/MinGW/lib/libssl.a;D:/cook/CppServer/CppServer/modules/OpenSSL/MinGW/lib/libcrypto.a -- Configuring done -- Generating done -- Build files have been written to: D:/cook/CppServer/CppServer/temp [ 1%] Built target cpp-optparse [ 3%] Built target fmt [ 10%] Built target zlib [ 11%] Built target asio [ 14%] Built target HdrHistogram [ 14%] Building CXX object modules/CppCommon/CMakeFiles/cppcommon.dir/source/errors/exceptions_handler.cpp.obj [ 15%] Building CXX object modules/CppCommon/CMakeFiles/cppcommon.dir/source/math/math.cpp.obj [ 16%] Building CXX object modules/CppCommon/CMakeFiles/cppcommon.dir/source/string/encoding.cpp.obj [ 16%] Building CXX object modules/CppCommon/CMakeFiles/cppcommon.dir/source/string/string_utils.cpp.obj [ 17%] Building CXX object modules/CppCommon/CMakeFiles/cppcommon.dir/source/system/console.cpp.obj [ 17%] Building CXX object modules/CppCommon/CMakeFiles/cppcommon.dir/source/system/cpu.cpp.obj [ 18%] Building CXX object modules/CppCommon/CMakeFiles/cppcommon.dir/source/system/dll.cpp.obj [ 18%] Building CXX object modules/CppBenchmark/CMakeFiles/cppbenchmark.dir/source/benchmark/system.cpp.obj D:\cook\CppServer\CppServer\modules\CppCommon\source\math\math.cpp: In static member function 'static uint64_t CppCommon::Math::MulDiv64(uint64_t, uint64_t, uint64_t)': D:\cook\CppServer\CppServer\modules\CppCommon\source\math\math.cpp:20:5: error: '__uint128_t' was not declared in this scope __uint128_t a = operant; ^~~~~~~~~~~ D:\cook\CppServer\CppServer\modules\CppCommon\source\math\math.cpp:20:5: note: suggested alternative: 'uint32_t' __uint128_t a = operant; ^~~~~~~~~~~ uint32_t D:\cook\CppServer\CppServer\modules\CppCommon\source\math\math.cpp:21:17: error: expected ';' before 'b' __uint128_t b = multiplier; ^ D:\cook\CppServer\CppServer\modules\CppCommon\source\math\math.cpp:22:17: error: expected ';' before 'c' __uint128_t c = divider; ^ D:\cook\CppServer\CppServer\modules\CppCommon\source\math\math.cpp:24:23: error: 'a' was not declared in this scope return (uint64_t)(a * b / c); ^ D:\cook\CppServer\CppServer\modules\CppCommon\source\math\math.cpp:24:27: error: 'b' was not declared in this scope return (uint64_t)(a * b / c); ^ D:\cook\CppServer\CppServer\modules\CppCommon\source\math\math.cpp:24:31: error: 'c' was not declared in this scope return (uint64_t)(a * b / c); ^ mingw32-make[2]: *** [modules\CppCommon\CMakeFiles\cppcommon.dir\build.make:287: modules/CppCommon/CMakeFiles/cppcommon.dir/source/math/math.cpp.obj] Error 1 mingw32-make[2]: *** Waiting for unfinished jobs.... D:\cook\CppServer\CppServer\modules\CppBenchmark\source\benchmark\system.cpp: In static member function 'static uint64_t CppBenchmark::System::MulDiv64(uint64_t, uint64_t, uint64_t)': D:\cook\CppServer\CppServer\modules\CppBenchmark\source\benchmark\system.cpp:716:5: error: '__uint128_t' was not declared in this scope __uint128_t a = operant; ^~~~~~~~~~~ D:\cook\CppServer\CppServer\modules\CppBenchmark\source\benchmark\system.cpp:716:5: note: suggested alternative: 'uint32_t' __uint128_t a = operant; ^~~~~~~~~~~ uint32_t D:\cook\CppServer\CppServer\modules\CppBenchmark\source\benchmark\system.cpp:717:17: error: expected ';' before 'b' __uint128_t b = multiplier; ^ D:\cook\CppServer\CppServer\modules\CppBenchmark\source\benchmark\system.cpp:718:17: error: expected ';' before 'c' __uint128_t c = divider; ^ D:\cook\CppServer\CppServer\modules\CppBenchmark\source\benchmark\system.cpp:720:23: error: 'a' was not declared in this scope return (uint64_t)(a * b / c); ^ D:\cook\CppServer\CppServer\modules\CppBenchmark\source\benchmark\system.cpp:720:27: error: 'b' was not declared in this scope return (uint64_t)(a * b / c); ^ D:\cook\CppServer\CppServer\modules\CppBenchmark\source\benchmark\system.cpp:720:31: error: 'c' was not declared in this scope return (uint64_t)(a * b / c); ^ mingw32-make[2]: *** [modules\CppBenchmark\CMakeFiles\cppbenchmark.dir\build.make:343: modules/CppBenchmark/CMakeFiles/cppbenchmark.dir/source/benchmark/system.cpp.obj] Error 1 mingw32-make[1]: *** [CMakeFiles\Makefile2:2080: modules/CppBenchmark/CMakeFiles/cppbenchmark.dir/all] Error 2 mingw32-make[1]: *** Waiting for unfinished jobs.... D:\cook\CppServer\CppServer\modules\CppCommon\source\errors\exceptions_handler.cpp: In static member function 'static void CppCommon::ExceptionsHandler::Impl::GetExceptionPointers(DWORD, EXCEPTION_POINTERS**)': D:\cook\CppServer\CppServer\modules\CppCommon\source\errors\exceptions_handler.cpp:442:9: error: expected '(' before '{' token { ^ D:\cook\CppServer\CppServer\modules\CppCommon\source\errors\exceptions_handler.cpp:443:13: error: 'mov' was not declared in this scope mov dword ptr [ContextRecord.Eax ], eax ^~~ D:\cook\CppServer\CppServer\modules\CppCommon\source\errors\exceptions_handler.cpp:436:24: error: unused variable 'dw' -Werror=unused-variable] volatile ULONG dw[(sizeof(CONTEXT) + sizeof(EXCEPTION_RECORD)) / sizeof(ULONG)]; ^~ cc1plus.exe: all warnings being treated as errors mingw32-make[2]: *** [modules\CppCommon\CMakeFiles\cppcommon.dir\build.make:161: modules/CppCommon/CMakeFiles/cppcommon.dir/source/errors/exceptions_handler.cpp.obj] Error 1 mingw32-make[1]: *** [CMakeFiles\Makefile2:2231: modules/CppCommon/CMakeFiles/cppcommon.dir/all] Error 2 mingw32-make: *** [Makefile:140: all] Error 2

    opened by amrkamal2025 7
  • Distributed Services / Surveyor Protocol

    Distributed Services / Surveyor Protocol

    Hi,

    Hope you are all well !

    I had a quick question about your interesting repo using nanomsg:

    I seek to create a distributed services tree for another project called find-object like described in this article (ref. repo)

    A GUI and console mode are available, and the interesting part is that you can handle an extensive set of options for launching the cli/tcp server (ref) with an .ini config file (link).

    I wanted to wrap them with cpp server, and build up some RPC/HTTP api endpoints (add/delete images or update config), and to launch 2 or 3 services with different configurations. On top, I wanted to re-use cpp server as an api gateway (surveyor) for bindings the 3 services (respondents) and aggregate the final response.

    The ultimate goal is to compare results for the same input image in real time from a stream of images. (ref); that's why I thought that the nanomsg's surveyor protocol could be a good fit.

    As I saw that you integrated some cpp nanomsg components to cpp server, I wanted to get your input or point of view about that.

    Questions: How would u see such distributed integration with your project ? Is it possible to manage also the configuration of your cpp server from configuration file (yaml or ini) ?

    Cheers, Richard

    opened by roscopecoltran 7
  • Including this in my own VS project

    Including this in my own VS project

    I'm trying to integrate a websocket server into an existing visual studio project. I've managed to build this from source and get a .lib but I'm not too sure how straightforward including the necessary headers into my project is.. Sorry I'm fairly new to building c++ dependencies outside of VS.

    opened by FocuzJS 4
  • performances

    performances

    Hello,

    I just looked over your repo and it's pretty amazing. Congrats ! All interfaces looks pretty nice and self explanatory.

    What I'm wonder it's the performance of this servers from a memory usage and requests/second they can serve point of view.

    Looking to your results and on what machine you run the tests I see the HTTP/HTTPS server performances being very poor. Have you compared your results with other solutions ?

    For example for websocket have you compared the HTTP and websocket performances with https://github.com/uNetworking/uWebSockets which seems a strong candidate ?

    Kind regards, Silviu

    opened by silviucpp 4
  • Errors about bfd_section_vma, bfd_section_size, and bfd_section_flags

    Errors about bfd_section_vma, bfd_section_size, and bfd_section_flags

    When executing unix.sh on Ubuntu 20, I get the following errors:

    [ 36%] Building CXX object modules/CppCommon/CMakeFiles/cppcommon.dir/source/system/stack_trace.cpp.o
    [ 36%] Building CXX object modules/CppCommon/CMakeFiles/cppcommon.dir/source/system/stack_trace_manager.cpp.o
    /home/CppServer/modules/CppCommon/source/system/stack_trace.cpp:165:50: error: macro "bfd_section_vma" requires 2 arguments, but only 1 given
                 bfd_vma vma = bfd_section_vma(section);
                                                      ^
    /home/CppServer/modules/CppCommon/source/system/stack_trace.cpp:169:61: error: macro "bfd_section_size" requires 2 arguments, but only 1 given
                 bfd_size_type secsize = bfd_section_size(section);
                                                                 ^
    /home/CppServer/modules/CppCommon/source/system/stack_trace.cpp: In constructor ‘CppCommon::StackTrace::StackTrace(int)’:
    /home/CppServer/modules/CppCommon/source/system/stack_trace.cpp:162:18: error: ‘bfd_section_flags’ was not declared in this scope
                 if ((bfd_section_flags(section) & SEC_ALLOC) == 0)
                      ^~~~~~~~~~~~~~~~~
    /home/CppServer/modules/CppCommon/source/system/stack_trace.cpp:162:18: note: suggested alternative: ‘bfd_set_section_flags’
                 if ((bfd_section_flags(section) & SEC_ALLOC) == 0)
                      ^~~~~~~~~~~~~~~~~
                      bfd_set_section_flags
    /home/CppServer/modules/CppCommon/source/system/stack_trace.cpp:165:27: error: ‘bfd_section_vma’ was not declared in this scope
                 bfd_vma vma = bfd_section_vma(section);
                               ^~~~~~~~~~~~~~~
    /home/CppServer/modules/CppCommon/source/system/stack_trace.cpp:165:27: note: suggested alternative: ‘bfd_scan_vma’
                 bfd_vma vma = bfd_section_vma(section);
                               ^~~~~~~~~~~~~~~
                               bfd_scan_vma
    /home/CppServer/modules/CppCommon/source/system/stack_trace.cpp:169:37: error: ‘bfd_section_size’ was not declared in this scope
                 bfd_size_type secsize = bfd_section_size(section);
                                         ^~~~~~~~~~~~~~~~
    /home/CppServer/modules/CppCommon/source/system/stack_trace.cpp:169:37: note: suggested alternative: ‘bfd_set_gp_size’
                 bfd_size_type secsize = bfd_section_size(section);
                                         ^~~~~~~~~~~~~~~~
                                         bfd_set_gp_size
    [ 37%] Building CXX object modules/CppCommon/CMakeFiles/cppcommon.dir/source/system/stream.cpp.o
    modules/CppCommon/CMakeFiles/cppcommon.dir/build.make:453: recipe for target 'modules/CppCommon/CMakeFiles/cppcommon.dir/source/system/stack_trace.cpp.o' failed
    make[2]: *** [modules/CppCommon/CMakeFiles/cppcommon.dir/source/system/stack_trace.cpp.o] Error 1
    make[2]: *** Waiting for unfinished jobs....
    CMakeFiles/Makefile2:1788: recipe for target 'modules/CppCommon/CMakeFiles/cppcommon.dir/all' failed
    make[1]: *** [modules/CppCommon/CMakeFiles/cppcommon.dir/all] Error 2
    Makefile:145: recipe for target 'all' failed
    make: *** [all] Error 2
    
    

    All of these seem to be coming from CppCommon.

    opened by arjangupta 3
  • Does not compile in a bunch of Visual Studio and Debian 10

    Does not compile in a bunch of Visual Studio and Debian 10

    Hello! I am trying to compile an example of TCP chat server from Visual Studio in connection to Debian 10. But when compiling on the Linux side, I get the following errors:

    1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in function void __gnu_cxx::new_allocator<CppServer::Asio::Service>::construct<CppServer::Asio::Service>(CppServer::Asio::Service*)': 1>/usr/include/c++/8/bits/shared_ptr_base.h(541): error : undefined reference toCppServer::Asio::Service::Service(int, bool)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in function CTCPServer::TCPServer(std::shared_ptr<CppServer::Asio::Service> const&, int, CppServer::Asio::InternetProtocol)': 1>D:\MainFiles\desctop\BlockadeClassic\MAIN_SERVER_CLASSIC_LINUX\ServerHandler.h(45): error : undefined reference toCppServer::Asio::TCPServer::TCPServer(std::shared_ptrCppServer::Asio::Service const&, int, CppServer::Asio::InternetProtocol)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in function CppServer::Asio::TCPSession::Disconnect()': 1>/usr/include/CppServer/include/server/asio/tcp_session.h(75): error : undefined reference toCppServer::Asio::TCPSession::Disconnect(bool)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in function CTCPSession::TCPSession(std::shared_ptr<CppServer::Asio::TCPServer> const&)': 1>D:\MainFiles\desctop\BlockadeClassic\MAIN_SERVER_CLASSIC_LINUX\ServerHandler.h(9): error : undefined reference toCppServer::Asio::TCPSession::TCPSession(std::shared_ptrCppServer::Asio::TCPServer const&)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in function CppServer::Asio::Service::~Service()': 1>/usr/include/CppServer/include/server/asio/service.h(70): error : undefined reference tovtable for CppServer::Asio::Service' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in function CppCommon::operator<<(std::ostream&, CppCommon::UUID const&)': 1>/usr/include/CppCommon/include/system/uuid.h(97): error : undefined reference toCppCommon::UUID::stringabi:cxx11 const' 1>/usr/bin/ld : error : /usr/include/CppCommon/include/system/uuid.h:97: undefined reference to CppCommon::UUID::string[abi:cxx11]() const' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in functionCppServer::Asio::TCPSession::~TCPSession()': 1>/usr/include/CppServer/include/server/asio/tcp_session.h(39): error : undefined reference to vtable for CppServer::Asio::TCPSession' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in functionasio::detail::io_object_impl<asio::detail::reactive_socket_serviceasio::ip::tcp, asio::executor>::~io_object_impl()': 1>/usr/include/asio/asio/include/asio/detail/io_object_impl.hpp(116): error : undefined reference to asio::detail::reactive_socket_service_base::destroy(asio::detail::reactive_socket_service_base::base_implementation_type&)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in functionCppServer::Asio::TCPSession::~TCPSession()': 1>/usr/include/CppServer/include/server/asio/tcp_session.h(39): error : undefined reference to vtable for CppServer::Asio::TCPSession' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in functionasio::detail::io_object_impl<asio::detail::reactive_socket_serviceasio::ip::tcp, asio::executor>::~io_object_impl()': 1>/usr/include/asio/asio/include/asio/detail/io_object_impl.hpp(116): error : undefined reference to asio::detail::reactive_socket_service_base::destroy(asio::detail::reactive_socket_service_base::base_implementation_type&)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in functionCppServer::Asio::Service::~Service()': 1>/usr/include/CppServer/include/server/asio/service.h(70): error : undefined reference to vtable for CppServer::Asio::Service' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in functionCppServer::Asio::TCPServer::~TCPServer()': 1>/usr/include/CppServer/include/server/asio/tcp_server.h(57): error : undefined reference to vtable for CppServer::Asio::TCPServer' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in functionasio::detail::io_object_impl<asio::detail::reactive_socket_serviceasio::ip::tcp, asio::executor>::~io_object_impl()': 1>/usr/include/asio/asio/include/asio/detail/io_object_impl.hpp(116): error : undefined reference to asio::detail::reactive_socket_service_base::destroy(asio::detail::reactive_socket_service_base::base_implementation_type&)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in functionCppServer::Asio::TCPServer::~TCPServer()': 1>/usr/include/CppServer/include/server/asio/tcp_server.h(57): error : undefined reference to vtable for CppServer::Asio::TCPServer' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in functionasio::detail::io_object_impl<asio::detail::reactive_socket_serviceasio::ip::tcp, asio::executor>::~io_object_impl()': 1>/usr/include/asio/asio/include/asio/detail/io_object_impl.hpp(116): error : undefined reference to asio::detail::reactive_socket_service_base::destroy(asio::detail::reactive_socket_service_base::base_implementation_type&)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in functionCppServer::Asio::Service::~Service()': 1>/usr/include/CppServer/include/server/asio/service.h(70): error : undefined reference to vtable for CppServer::Asio::Service' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in functionasio::error::get_system_category()': 1>/usr/include/asio/asio/include/asio/error.hpp(228): error : undefined reference to asio::system_category()' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in function__static_initialization_and_destruction_0': 1>/usr/include/asio/asio/include/asio/error.hpp(261): error : undefined reference to asio::error::get_netdb_category()' 1>/usr/bin/ld : error : /usr/include/asio/asio/include/asio/error.hpp:264: undefined reference toasio::error::get_addrinfo_category()' 1>/usr/bin/ld : error : /usr/include/asio/asio/include/asio/error.hpp:267: undefined reference to asio::error::get_misc_category()' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o: in function__static_initialization_and_destruction_0': 1>/usr/include/asio/asio/include/asio/ssl/error.hpp(37): error : undefined reference to asio::error::get_ssl_category()' 1>/usr/bin/ld : error : /usr/include/asio/asio/include/asio/ssl/error.hpp:74: undefined reference toasio::ssl::error::get_stream_category()' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTI11CTCPSession[_ZTI11CTCPSession]+0x10): undefined reference to typeinfo for CppServer::Asio::TCPSession' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTI10CTCPServer[_ZTI10CTCPServer]+0x10): undefined reference totypeinfo for CppServer::Asio::TCPServer' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTV11CTCPSession[_ZTV11CTCPSession]+0x28): undefined reference to CppServer::Asio::TCPSession::Send(void const*, unsigned long)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTV11CTCPSession[_ZTV11CTCPSession]+0x38): undefined reference toCppServer::Asio::TCPSession::Send(void const*, unsigned long, CppCommon::Timespan const&)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTV11CTCPSession[_ZTV11CTCPSession]+0x48): undefined reference to CppServer::Asio::TCPSession::SendAsync(void const*, unsigned long)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTV11CTCPSession[_ZTV11CTCPSession]+0x58): undefined reference toCppServer::Asio::TCPSession::Receive(void*, unsigned long)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTV11CTCPSession[_ZTV11CTCPSession]+0x60): undefined reference to CppServer::Asio::TCPSession::Receive[abi:cxx11](unsigned long)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTV11CTCPSession[_ZTV11CTCPSession]+0x68): undefined reference toCppServer::Asio::TCPSession::Receive(void*, unsigned long, CppCommon::Timespan const&)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTV11CTCPSession[_ZTV11CTCPSession]+0x70): undefined reference to CppServer::Asio::TCPSession::Receive[abi:cxx11](unsigned long, CppCommon::Timespan const&)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTV11CTCPSession[_ZTV11CTCPSession]+0x78): undefined reference toCppServer::Asio::TCPSession::ReceiveAsync()' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTV10CTCPServer[_ZTV10CTCPServer]+0x20): undefined reference to CppServer::Asio::TCPServer::Start()' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTV10CTCPServer[_ZTV10CTCPServer]+0x28): undefined reference toCppServer::Asio::TCPServer::Stop()' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTV10CTCPServer[_ZTV10CTCPServer]+0x30): undefined reference to CppServer::Asio::TCPServer::Restart()' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTV10CTCPServer[_ZTV10CTCPServer]+0x38): undefined reference toCppServer::Asio::TCPServer::Multicast(void const*, unsigned long)' 1>/usr/bin/ld : error : /home/nollin/projects/MAIN_SERVER_CLASSIC_LINUX/obj/x64/Release/ServerHandler.o:(.data.rel.ro._ZTV10CTCPServer[_ZTV10CTCPServer]+0x48): undefined reference to `CppServer::Asio::TCPServer::DisconnectAll()'

    What could be wrong with Asio? Sorry if I asked stupidity - after several days of trying to compile, my head is already cloudy.

    opened by MuravyevArtem 3
  • Compiling error

    Compiling error

    Hi!

    I got an error during compiling CppServer, I'm not so familiar with cmake so I can't get to work. Here is the error: -- Could NOT find LIBUUID (missing: LIBUUID_LIBRARY LIBUUID_INCLUDE_DIR) -- Could NOT find LIBVLD (missing: LIBVLD_LIBRARY)

    CppServer/modules/CppCommon/source/system/uuid.cpp:12:10: fatal error: uuid/uuid.h: no such file or directory #include <uuid/uuid.h> ^~~~~~~~~~~~~ compilation terminated. modules/CppCommon/CMakeFiles/cppcommon.dir/build.make:758: recipe for target 'modules/CppCommon/CMakeFiles/cppcommon.dir/source/system/uuid.cpp.o' failed make[2]: *** [modules/CppCommon/CMakeFiles/cppcommon.dir/source/system/uuid.cpp.o] Error 1 CMakeFiles/Makefile2:1378: recipe for target 'modules/CppCommon/CMakeFiles/cppcommon.dir/all' failed make[1]: *** [modules/CppCommon/CMakeFiles/cppcommon.dir/all] Error 2 Makefile:140: recipe for target 'all' failed make: *** [all] Error 2

    Can I get a little help? Thanks!

    opened by toma3757 3
  • TCPSession::onReceived only receives part of the buffer sent by client

    TCPSession::onReceived only receives part of the buffer sent by client

    I create a TCPSeesion followed by the TCP Chat example. However, I found my TCPSession can not received the whole buffer in one call of onReceived function when my client sent a large amount of data. The remaining data sent by client will be received by the next call of onReceived function. It seems receiving data by chuncks even the client sends the data in one sending.

    How can I know my server has received all the data sent by client at a sending?

    opened by wsyOverflow 2
  • How to connect to a wss:// URL ?

    How to connect to a wss:// URL ?

    Hi, Your library looks very clean. How do I connect a ws client to a wss:// url? In examples I only see IP address. Do I have to create my own DNS resolver?

    opened by whyCPPgofast 2
  • Invalid left shift

    Invalid left shift

    | /build/cppserver/1.0.0-r0/git/source/server/ws/ws.cpp: In member function 'void CppServer::WS::WebSocket::PrepareReceiveFrame(const void*, size_t)':
    | /build/cppserver/1.0.0-r0/git/source/server/ws/ws.cpp:333:55: error: left shift count >= width of type [-Werror=shift-count-overflow]
    |   333 |             payload = (((size_t)_ws_receive_buffer[2] << 56) | ((size_t)_ws_receive_buffer[3] << 48) | ((size_t)_ws_receive_buffer[4] << 40) | ((size_t)_ws_receive_buffer[5] << 32) | ((size_t)_ws_receive_buffer[6] << 24) | ((size_t)_ws_receive_buffer[7] << 16) | ((size_t)_ws_receive_buffer[8] << 8) | ((size_t)_ws_receive_buffer[9] << 0));
    |       |                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
    | /build/cppserver/1.0.0-r0/git/source/server/ws/ws.cpp:333:95: error: left shift count >= width of type [-Werror=shift-count-overflow]
    |   333 |             payload = (((size_t)_ws_receive_buffer[2] << 56) | ((size_t)_ws_receive_buffer[3] << 48) | ((size_t)_ws_receive_buffer[4] << 40) | ((size_t)_ws_receive_buffer[5] << 32) | ((size_t)_ws_receive_buffer[6] << 24) | ((size_t)_ws_receive_buffer[7] << 16) | ((size_t)_ws_receive_buffer[8] << 8) | ((size_t)_ws_receive_buffer[9] << 0));
    |       |                                                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
    | /build/cppserver/1.0.0-r0/git/source/server/ws/ws.cpp:333:135: error: left shift count >= width of type [-Werror=shift-count-overflow]
    |   333 |             payload = (((size_t)_ws_receive_buffer[2] << 56) | ((size_t)_ws_receive_buffer[3] << 48) | ((size_t)_ws_receive_buffer[4] << 40) | ((size_t)_ws_receive_buffer[5] << 32) | ((size_t)_ws_receive_buffer[6] << 24) | ((size_t)_ws_receive_buffer[7] << 16) | ((size_t)_ws_receive_buffer[8] << 8) | ((size_t)_ws_receive_buffer[9] << 0));
    |       |                                                                                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
    | /build/cppserver/1.0.0-r0/git/source/server/ws/ws.cpp:333:175: error: left shift count >= width of type [-Werror=shift-count-overflow]
    |   333 |             payload = (((size_t)_ws_receive_buffer[2] << 56) | ((size_t)_ws_receive_buffer[3] << 48) | ((size_t)_ws_receive_buffer[4] << 40) | ((size_t)_ws_receive_buffer[5] << 32) | ((size_t)_ws_receive_buffer[6] << 24) | ((size_t)_ws_receive_buffer[7] << 16) | ((size_t)_ws_receive_buffer[8] << 8) | ((size_t)_ws_receive_buffer[9] << 0));
    |       |                                                                                                                                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
    

    I'm building for an arm platform where size_t is 32 bit

    opened by hellow554 2
  • Add git TAGs to help versioning

    Add git TAGs to help versioning

    It'd be great to have some git tags to help us here packaging CppServer in our pipelines.

    I've already opened a similar issue on CppCommon: https://github.com/chronoxor/CppCommon/issues/4

    opened by tarc 2
  • build error

    build error

    error: macro "bfd_section_vma" requires 2 arguments, but only 1 given bfd_vma vma = bfd_section_vma(section); ^ /home/work/CppServer/modules/CppCommon/source/system/stack_trace.cpp:174:61: error: macro "bfd_section_size" requires 2 arguments, but only 1 given bfd_size_type secsize = bfd_section_size(section); ^ /home/work/CppServer/modules/CppCommon/source/system/stack_trace.cpp: In constructor ‘CppCommon::StackTrace::StackTrace(int)’: /home/work/CppServer/modules/CppCommon/source/system/stack_trace.cpp:167:18: error: ‘bfd_section_flags’ was not declared in this scope if ((bfd_section_flags(section) & SEC_ALLOC) == 0) ^~~~~~~~~~~~~~~~~ /home/work/CppServer/modules/CppCommon/source/system/stack_trace.cpp:167:18: note: suggested alternative: ‘bfd_set_section_flags’ if ((bfd_section_flags(section) & SEC_ALLOC) == 0) ^~~~~~~~~~~~~~~~~ bfd_set_section_flags /home/work/CppServer/modules/CppCommon/source/system/stack_trace.cpp:170:27: error: ‘bfd_section_vma’ was not declared in this scope bfd_vma vma = bfd_section_vma(section); ^~~~~~~~~~~~~~~ /home/work/CppServer/modules/CppCommon/source/system/stack_trace.cpp:170:27: note: suggested alternative: ‘bfd_scan_vma’ bfd_vma vma = bfd_section_vma(section); ^~~~~~~~~~~~~~~ bfd_scan_vma /home/work/CppServer/modules/CppCommon/source/system/stack_trace.cpp:174:37: error: ‘bfd_section_size’ was not declared in this scope bfd_size_type secsize = bfd_section_size(section); ^~~~~~~~~~~~~~~~ /home/work/CppServer/modules/CppCommon/source/system/stack_trace.cpp:174:37: note: suggested alternative: ‘bfd_set_gp_size’ bfd_size_type secsize = bfd_section_size(section); ^~~~~~~~~~~~~~~~ bfd_set_gp_size [ 33%] Building CXX object modules/CppCommon/CMakeFiles/cppcommon.dir/source/system/stack_trace_manager.cpp.o modules/CppCommon/CMakeFiles/cppcommon.dir/build.make:453: recipe for target 'modules/CppCommon/CMakeFiles/cppcommon.dir/source/system/stack_trace.cpp.o' failed make[2]: *** [modules/CppCommon/CMakeFiles/cppcommon.dir/source/system/stack_trace.cpp.o] Error 1 make[2]: *** Waiting for unfinished jobs.... CMakeFiles/Makefile2:1971: recipe for target 'modules/CppCommon/CMakeFiles/cppcommon.dir/all' failed make[1]: *** [modules/CppCommon/CMakeFiles/cppcommon.dir/all] Error 2 Makefile:145: recipe for target 'all' failed make: *** [all] Error 2

    opened by Herinbul 0
  • Unable to compile sample UDP echo server

    Unable to compile sample UDP echo server

    conan:

    [requires]
    cppserver/1.0.1.0
    
    [generators]
    CMakeDeps
    CMakeToolchain
    

    CMakeLists:

    cmake_minimum_required(VERSION 3.24)
    
    project(udplib LANGUAGES C CXX VERSION 0.0.1 DESCRIPTION "udplib")
    
    add_definitions("-std=c++11")
    
    find_package(cppserver)
    add_executable(${PROJECT_NAME} src/main.cc ${HEADERS})
    target_link_libraries(${PROJECT_NAME} cppserver::cppserver)
    

    error:

    [ 50%] Building CXX object CMakeFiles/udplib.dir/src/main.cc.o
    In file included from /Users/denismakogon/go/src/github.com/denismakogon/udplib/src/main.cc:1:
    In file included from /Users/denismakogon/.conan/data/cppserver/1.0.1.0/_/_/package/7013dbe3bb4a95ca2ea1195c65c0d63529763c20/include/server/asio/udp_server.h:12:
    In file included from /Users/denismakogon/.conan/data/cppserver/1.0.1.0/_/_/package/7013dbe3bb4a95ca2ea1195c65c0d63529763c20/include/server/asio/service.h:15:
    In file included from /Users/denismakogon/.conan/data/cppcommon/1.0.2.0/_/_/package/49beb6ac68a9c74359a1b46f2da1643fab69036c/include/threads/thread.h:164:
    /Users/denismakogon/.conan/data/cppcommon/1.0.2.0/_/_/package/49beb6ac68a9c74359a1b46f2da1643fab69036c/include/threads/thread.inl:47:25: warning: initialized lambda captures are a C++14 extension [-Wc++14-extensions]
        return std::thread([fn = fn, args...]()
                            ^
    1 warning generated.
    [100%] Linking CXX executable bin/udplib
    ld: warning: directory not found for option '-L/opt/homebrew/opt/llvm/lib'
    Undefined symbols for architecture arm64:
      "_CONF_modules_unload", referenced from:
          asio::ssl::detail::openssl_init_base::do_init::~do_init() in main.cc.o
      "_ERR_reason_error_string", referenced from:
          asio::error::detail::ssl_category::message(int) const in main.cc.o
      "CppServer::Asio::Service::Service(int, bool)", referenced from:
          std::__1::__shared_ptr_emplace<CppServer::Asio::Service, std::__1::allocator<CppServer::Asio::Service> >::__shared_ptr_emplace<>(std::__1::allocator<CppServer::Asio::Service>) in main.cc.o
      "CppServer::Asio::UDPServer::ReceiveAsync()", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::MulticastAsync(void const*, unsigned long)", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::Send(asio::ip::basic_endpoint<asio::ip::udp> const&, void const*, unsigned long)", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::Send(asio::ip::basic_endpoint<asio::ip::udp> const&, void const*, unsigned long, CppCommon::Timespan const&)", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::Stop()", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::Start(asio::ip::basic_endpoint<asio::ip::udp> const&)", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::Start(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int)", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::Start()", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::Receive(asio::ip::basic_endpoint<asio::ip::udp>&, void*, unsigned long)", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::Receive(asio::ip::basic_endpoint<asio::ip::udp>&, void*, unsigned long, CppCommon::Timespan const&)", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::Receive(asio::ip::basic_endpoint<asio::ip::udp>&, unsigned long)", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::Receive(asio::ip::basic_endpoint<asio::ip::udp>&, unsigned long, CppCommon::Timespan const&)", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::Restart()", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::Multicast(void const*, unsigned long)", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::Multicast(void const*, unsigned long, CppCommon::Timespan const&)", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::SendAsync(asio::ip::basic_endpoint<asio::ip::udp> const&, void const*, unsigned long)", referenced from:
          vtable for EchoServer in main.cc.o
      "CppServer::Asio::UDPServer::UDPServer(std::__1::shared_ptr<CppServer::Asio::Service> const&, int, CppServer::Asio::InternetProtocol)", referenced from:
          EchoServer::EchoServer(std::__1::shared_ptr<CppServer::Asio::Service> const&, int, CppServer::Asio::InternetProtocol) in main.cc.o
      "typeinfo for CppServer::Asio::UDPServer", referenced from:
          typeinfo for EchoServer in main.cc.o
      "vtable for CppServer::Asio::UDPServer", referenced from:
          CppServer::Asio::UDPServer::~UDPServer() in main.cc.o
      NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
    ld: symbol(s) not found for architecture arm64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    make[2]: *** [bin/udplib] Error 1
    make[1]: *** [CMakeFile
    
    opened by denismakogon 3
  • fmt header dependncies in cppcommon which bleed into cppserver

    fmt header dependncies in cppcommon which bleed into cppserver

    Hi, I ran into this when I included cppserver in a custom C++ project, and was specifically including server/asio/tcp_client.h. This file is including several files from CppCommon some of them (for example: /cppserver/modules/CppCommon/include/system/stack_trace.inl and /cppserver/modules/CppCommon/include/system/source_location.inl) depend on the fmt library but do not specifically include the fmt header file they depend on. This creates an issue for compilation unless the user will include the fmt header before including the high level file from cppserver So for server/asio/tcp_client.h, this is required:

    cppserver/modules/CppCommon/modules/fmt/include/fmt/ostream.h"
    server/asio/tcp_client.h
    

    I think it would be better if these files explicitly include the fmt header file they depend on.

    opened by eniv 4
  • How many HTTP connections can CppServer simultaneously hold on to?

    How many HTTP connections can CppServer simultaneously hold on to?

    Basically as stated - separate from high throughput demonstrated in the benchmarks, how many requests can CppServer hold onto while I work on generating a response?

    opened by Fractal-Anaphora 0
  • How to set SNI & connect to wss:// ?

    How to set SNI & connect to wss:// ?

    Hi @chronoxor,

    Really liking the design of CppServer!....however, unfortunately, I am running into issues attempting to connect to a wss:// endpoint.

    In general, I am unable to get a simple example of connecting working so any help explaining how to correctly resolve and connect to a websocket endpoint specified by a wss:// uri would be greatly appreciated!

    For example to connect to wss://ws.okx.com:8443/ws/v5/public (taken from here) I attempted the following based on the wss client example:

     // ...int main() {
    
      // Create a new Asio service
      auto service = std::make_shared<AsioService>();
      service->Start();
    
    
      // Create and prepare a new SSL client context
      auto context = std::make_shared<CppServer::Asio::SSLContext>(asio::ssl::context::tlsv12);
      context->set_default_verify_paths();
      context->set_root_certs();
      context->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
      context->load_verify_file("../external/CppServer/tools/certificates/ca.pem");
    
      // Use TCPResolver to lookup DNS
      // See: https://github.com/chronoxor/CppServer/issues/55
      auto resolver = std::make_shared<CppServer::Asio::TCPResolver>(service);
    
     // @NOTE ClientWebsocket is a child class of `public CppServer::WS::WSSClient`
      auto ws = std::make_shared<ClientWebsocket>(service, context, "ws.okx.com", 8443);
      ws->Connect(resolver);
    

    and the upgrade request attempt:

    
    class ClientWebsocket : public CppServer::WS::WSSClient
    {
    public:
      using CppServer::WS::WSSClient::WSSClient;
    protected:
      void onWSConnecting(CppServer::HTTP::HTTPRequest &request) override
      {
        request.SetBegin("GET", "/ws/v5/public", "HTTP/2");
        request.SetHeader("Host", address() + ":8443"); // @todo
        request.SetHeader("Upgrade", "websocket");
        request.SetHeader("Connection", "upgrade");
        request.SetHeader("Sec-WebSocket-Key", CppCommon::Encoding::Base64Encode(ws_nonce()));
        request.SetHeader("Accept", "/");
        // request.SetHeader("Sec-WebSocket-Version", "13");
        request.SetHeader("User-Agent", "beast.v1");
      }
    

    This did not work, and my comments are:

    (1) Do I need to set SNI somewhere on the stream native handle (using SSL_set_tlsext_host_name) (2) Why (once SNI is set) the upgrade request is not working? If you have any experience with this.


    NOTE: something like this seemed to get round initial SSL v3 handshake errors

    bool SSLClient::Connect(const std::shared_ptr<TCPResolver>& resolver) {
     // ...
    
        std::cout << "Setting SNI Hostname: " << _address << std::endl;
        if(SSL_set_tlsext_host_name(_stream.native_handle(), _address.c_str())) {
            std::cout << "Success!" << std::endl;
        }
        else {
            std::cout << "Failed!" << std::endl;
        }
    // ...
    
    
    opened by davidtwomey 2
Releases(1.0.2.0)
Owner
Ivan Shynkarenka
Cross-platform C++, highload servers, low latency, trading platforms, exchanges, crytpo markets, communication protocols, TCP, UDP, WebSockets, FIX, MT4, MT5.
Ivan Shynkarenka
Ole Christian Eidheim 741 Nov 2, 2022
Wrapper for linux TCP/UDP/unix/USB socket connections

Socket Connection wrapper shared library Shared library that realize sockets connections and could transfer data-packages. Navigation Navigation Insta

Dmitry Golgovsky 7 Dec 21, 2021
Small and fast cross-platform networking library, with support for messaging, IPv6, HTTP, SSL and WebSocket.

frnetlib Frnetlib, is a cross-platform, small and fast networking library written in C++. There are no library dependencies (unless you want to use SS

Fred Nicolson 22 May 16, 2022
A modern C++ network library for developing high performance network services in TCP/UDP/HTTP protocols.

evpp Introduction 中文说明 evpp is a modern C++ network library for developing high performance network services using TCP/UDP/HTTP protocols. evpp provid

Qihoo 360 3.1k Nov 18, 2022
Asynchronous, Header-only C++ HTTP-over-(TCP|UNIX Socket|STDIO) Library

CXXHTTP A C++ library implementing an asynchronous HTTP server and client. To clone this library, make sure you also clone the submodules. The --recur

null 25 Mar 19, 2021
Provide translation, currency conversion, and voting services. First using telnet you create a connection to a TCP socket, then the server connects to 3 UDP sockets hosted on other servers to do tasks.

to run micro servers g++ translator.cpp -o translator ./translator <port 1> g++ voting.cpp -o voting ./voting <port 2> g++ currency_converter.cpp -o c

Jacob Artuso 1 Oct 29, 2021
A protocol for secure client/server connections over UDP

netcode netcode is a simple connection based client/server protocol built on top of UDP. It has the following features: Encrypted and signed packets S

The Network Protocol Company 2.2k Nov 24, 2022
A protocol for secure client/server connections over UDP

netcode netcode is a simple connection based client/server protocol built on top of UDP. It has the following features: Encrypted and signed packets S

The Network Protocol Company 2.2k Nov 24, 2022
Asynchronous SSL TCP Library for ESP32.

Asynchronous SSL TCP Library for ESP32. This library is the base for future and more advanced Async SSL libraries, such as AsyncSSLWebServer, AsyncHTTPSRequest

Khoi Hoang 11 Nov 22, 2022
Cross-platform, efficient, customizable, and robust asynchronous HTTP/WebSocket server C++14 library with the right balance between performance and ease of use

What Is RESTinio? RESTinio is a header-only C++14 library that gives you an embedded HTTP/Websocket server. It is based on standalone version of ASIO

Stiffstream 912 Nov 25, 2022
Windows named pipe server that forwards connections to given TCP server

PipeTcp An asynchronous Windows named pipe server that forwards connections to given TCP server. Pre-built binaries can be found in Releases. Invocati

Jinoh Kang 5 Nov 3, 2022
cuehttp is a modern c++ middleware framework for http(http/https)/websocket(ws/wss).

cuehttp 简介 cuehttp是一个使用Modern C++(C++17)编写的跨平台、高性能、易用的HTTP/WebSocket框架。基于中间件模式可以方便、高效、优雅的增加功能。cuehttp基于boost.asio开发,使用picohttpparser进行HTTP协议解析。内部依赖了nl

xcyl 28 Nov 18, 2022
Portable, single-file, protocol-agnostic TCP and UDP socket wrapper, primarily for game networking

Documentation This is a header-only library, as such most of its functional documentation is contained within the "header section" of the source code

null 65 Aug 29, 2022
LAppS - Lua Application Server for micro-services with default communication over WebSockets. The fastest and most vertically scalable WebSockets server implementation ever. Low latency C++ <-> Lua stack roundtrip.

LAppS - Lua Application Server This is an attempt to provide very easy to use Lua Application Server working over WebSockets protocol (RFC 6455). LApp

null 48 Oct 13, 2022
Pushpin is a reverse proxy server written in C++ that makes it easy to implement WebSocket, HTTP streaming, and HTTP long-polling services.

Pushpin is a reverse proxy server written in C++ that makes it easy to implement WebSocket, HTTP streaming, and HTTP long-polling services. The project is unique among realtime push solutions in that it is designed to address the needs of API creators. Pushpin is transparent to clients and integrates easily into an API stack.

Fanout 3.2k Nov 24, 2022
Built a client-server application using TCP and UDP sockets, in which the clients can subscribe/unsubscribe to various topics.

Built a client-server application using TCP and UDP sockets, in which the clients can subscribe/unsubscribe to various topics.

null 1 Jun 22, 2022
websocket and http client and server library, coming with ws, a command line swiss army knife utility

Hello world IXWebSocket is a C++ library for WebSocket client and server development. It has minimal dependencies (no boost), is very simple to use an

Machine Zone, Inc. 358 Nov 19, 2022
A very simple, fast, multithreaded, platform independent HTTP and HTTPS server and client library implemented using C++11 and Boost.Asio.

A very simple, fast, multithreaded, platform independent HTTP and HTTPS server and client library implemented using C++11 and Boost.Asio. Created to be an easy way to make REST resources available from C++ applications.

Ole Christian Eidheim 2.4k Nov 22, 2022
A Lightweight and fully asynchronous WebSocket client library based on libev

libuwsc(中文) A Lightweight and fully asynchronous WebSocket client library based on libev for Embedded Linux. And provide Lua-binding. Why should I cho

Jianhui Zhao 285 Nov 17, 2022