Lightweight, header-only, Boost-based socket pool library

Overview

Stream-client

Language C++ Github releases Coverage Status License

This is a lightweight, header-only, Boost-based library providing client-side network primitives to easily organize and implement data transmission with remote endpoints.

This library:

  • Inspired by and built around Boost.Asio.
  • Provides high-level constructs as connector and connection pool.
  • Supports TCP/UDP/SSL/HTTP/HTTPS protocols.
  • Uses sockets with the same interface as boost::asio::ip ones.
  • Allows transparent timeout/deadline control for all operations.
  • Requires boost 1.65+ or 1.66+ if you are planning to use HTTP protocol.

Why

If you are writing software on C++, which communicates with other services as a client, you probably already came-across with the problem - need to implement connectivity layer to provide network transport to all related services. This is exactly what this library's aim to solve.

How to use

Sockets

Sockets are implemented on top of boost::asio::basic_socket and provide classes with timeout control, so in most cases it's enough to just call send()/receive()/write_some()/read_some() with a deadline or timeout. Data supplied to I/O operations should be wrapped into boost::asio::buffer. Basically these clients are timeout-wrapped boost::asio::ip sockets and have the same interface.

Client streams classes:

  • stream_client::tcp_client - plain TCP stream socket client. Supports send()/rececive() for admitted transfers of whole buffer along with write_some()/read_some() to transfer at least something.
  • stream_client::udp_client - plain UDP socket client. Supports only send()/receive() without any acknowledgment as per UDP specs.
  • stream_client::ssl::ssl_client - SSL-encrypted TCP client. Have the same functions as tcp_client plus SSL handshake and context control.
  • stream_client::http::http_client - HTTP client. Wraps tcp_client with boost::beast::http::parser and boost::beast::http::serializer and have perform() function to make request-response calls.
  • stream_client::http::https_client - HTTPS client. Same as http_client but uses ssl_client client underneath.

Example

const boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 12345);
const std::chrono::milliseconds connect_timeout(1000);
const std::chrono::milliseconds io_timeout(100);

// this makes connected socket and may take up to connect_timeout time
stream_client::tcp_client client(endpoint, connect_timeout, io_timeout);

// send() operation will transmit all contents of send_data or throw an error;
// also it will throw boost::asio::error::timed_out after io_timeout.
const std::string send_data = "test data";
client.send(boost::asio::buffer(send_data.data(), send_data.size()));

// receive() operation will read send_data.size() size or throw an error;
// also it will throw boost::asio::error::timed_out after io_timeout.
std::string recv_data(send_data.size(), '\0');
client.receive(boost::asio::buffer(&recv_data[0], send_data.size()));

// there are also non-throw overloads to these functions which
// will set boost::system::error_code instead of exception;

DNS resolver

Resolver is implemented around the same idea - make sync, timed DNS resolver, therefore it uses boost::asio::ip::basic_resolver to perform actual resolution within specified timeouts.

It is the class template with a single parameter - result protocol, also you can specify which type of IP endpoints you are interested in - IPv4, IPv6 or both. Resolution performed with resolve() call which has a similar signature as sockets operations - you are free to specify timeout/deadline or use default one.

Resolver classes:

  • stream_client::resolver::tcp_resolver - resolver which returns iterator of TCP endpoints.
  • stream_client::resolver::udp_resolver - resolver which returns iterator of UDP endpoints.

Example

const std::chrono::milliseconds resolve_timeout(5000);

stream_client::resolver::tcp_resolver resolver("localhost", "12345",
                                               resolve_timeout,
                                               stream_client::resolver::ip_family::ipv4);

// resolve() guaranteed to return at least one endpoint or will throw an error;
// it will throw boost::asio::error::timed_out after resolve_timeout.
auto endpoints_it = resolver.resolve();

// returned iterator is an instance of boost::asio::ip::basic_resolver::iterator<Protocol>

Connector

Connector uses resolver to perform DNS resolution and update the list of endpoints and uses them if requested with new_session(), to create a new socket of the specified protocol. The work of DNS resolver is wrapped into background thread which triggered upon creation or if there was an error in opening a new socket.

Target endpoint to open a new socket selected randomly from the DNS results, which makes it balanced connector to a remote host. Also, the connector allows specifying separate timeouts for resolution, connection, and I/O operation of new sockets.

Connector classes:

  • stream_client::connector::tcp_connector - TCP connector, to obtain stream_client::tcp_client sockets.
  • stream_client::connector::udp_connector - UDP connector, to obtain stream_client::udp_client sockets.
  • stream_client::connector::ssl_connector - TCP connector, to obtain stream_client::ssl::ssl_client sockets.
  • stream_client::connector::http_connector - HTTP connector, to obtain stream_client::http::http_client sockets.
  • stream_client::connector::https_connector - HTTPS connector, to obtain stream_client::http::https_client sockets.

Example

const std::chrono::milliseconds resolve_timeout(5000);
const std::chrono::milliseconds connect_timeout(1000);
const std::chrono::milliseconds io_timeout(100);

// this will return immediately, starting background thread for name resolution
stream_client::connector::tcp_connector connector("localhost", "12345",
                                                  resolve_timeout, connect_timeout, io_timeout,
                                                  stream_client::resolver::ip_family::ipv4);

// this will acquire new socket or throw;
// it will throw boost::asio::error::timed_out after connect_timeout
std::unique_ptr<stream_client::tcp_client> client = connector.new_session();

// use the client
const std::string send_data = "test data";
std::string recv_data(send_data.size(), '\0');
client->send(boost::asio::buffer(send_data.data(), send_data.size()));
client->receive(boost::asio::buffer(&recv_data[0], send_data.size()));

Connection pool

Represents container occupied with opened sockets. Uses connector to open new sockets in the background thread which is triggered once there are vacant places in the pool. User can call get_session() to obtain a socket from the pool and return_session() to give it back.

Limitations:

  1. Sockets that are already in the pool are not checked or maintained in any way. Hence, the pool doesn't guarantee that all sockets are opened at an arbitrary point in time due to the complexity of such checks for all supported protocols.
  2. Nothing specific done with sockets upon their return within return_session(). Therefore, if they have or will have pending data to read, it will stay there until reading.

Considering this, the best strategy to use a connection pool is such:

  1. Create it, specifying all timeouts as you need.
  2. Once created, use get_session() to obtain opened socket.
  3. Do needed I/O operations on the socket.
  4. If 2-3 succeed, return it back with return_session(), else repeat point 2.

It is important to discard sockets on failure and not reuse them, or request-response management will get nasty.

Connection pools:

  • stream_client::connector::tcp_pool - pool of stream_client::tcp_client sockets.
  • stream_client::connector::udp_pool - pool of stream_client::udp_client sockets.
  • stream_client::connector::ssl_pool - pool of stream_client::ssl::ssl_client sockets.
  • stream_client::connector::http_pool - pool of stream_client::http::http_client sockets.
  • stream_client::connector::https_pool - pool of stream_client::http::https_client sockets.

Example

const std::chrono::milliseconds resolve_timeout(5000);
const std::chrono::milliseconds connect_timeout(1000);
const std::chrono::milliseconds io_timeout(100);

auto connector_pool =
    std::make_shared<stream_client::connector::tcp_pool>("localhost", "12345",
                                                         resolve_timeout, connect_timeout, io_timeout,
                                                         stream_client::resolver::ip_family::ipv4);
const size_t threads_num = 10;
std::vector<std::thread> threads;
const std::string send_data = "test data";
std::mutex stdout_mutex;

for (size_t i = 0; i < threads_num; ++i) {
    threads.emplace_back([&send_data, &stdout_mutex, connector_pool]() {
        std::string recv_data(send_data.size(), '\0');

        auto client = connector_pool->get_session();
        // both these calls will throw exception on error or timeout
        client->send(boost::asio::buffer(send_data.data(), send_data.size()));
        client->receive(boost::asio::buffer(&recv_data[0], send_data.size()));
        // if there was no exception, return it
        connector_pool->return_session(std::move(client));

        const std::lock_guard<std::mutex> lk(stdout_mutex);
        std::cout << std::this_thread::get_id() << ": " << recv_data << std::endl;
    });
}

for (auto& t : threads) {
    t.join();
}

How to build

This library supposed to be somewhat multi-platform, however, it was tested and mainly used on ubuntu and macOS.
Prefer out-of-source building.

Ubuntu dependencies

sudo apt update
sudo apt install build-essential cmake libboost-dev libboost-system-dev libssl-dev

macOS dependencies

brew install cmake pkg-config icu4c openssl boost

To build:

cmake -H. -Bbuild
cmake --build ./build

To install (sudo may be required):

cmake -H. -Bbuild -DSTREAMCLIENT_BUILD_TESTING=OFF -DSTREAMCLIENT_BUILD_DOCS=OFF -DSTREAMCLIENT_BUILD_EXAMPLES=OFF
cmake --build ./build --target install

Or test:

cmake -H. -Bbuild -DSTREAMCLIENT_BUILD_TESTING=ON -DSTREAMCLIENT_BUILD_DOCS=OFF -DSTREAMCLIENT_BUILD_EXAMPLES=OFF
cmake --build ./build
cmake -E chdir ./build ctest --output-on-failure

All these commands assume you are in stream-client root folder

Cmake options

  • CMAKE_BUILD_TYPE - build type. RelWithDebInfo by default.
  • BUILD_SHARED_LIBS - build shared or static library. ON by default.
  • STREAMCLIENT_BUILD_TESTING - build tests or not. OFF by default
  • STREAMCLIENT_BUILD_EXAMPLES - build library examples or not. OFF by default.
  • STREAMCLIENT_BUILD_DOCS – build html (sphinx) reference docs. OFF by default.
  • OPENSSL_USE_STATIC_LIBS - link statically or dynamically against found openssl. If BUILD_SHARED_LIBS is OFF then this options is set.
  • OPENSSL_ROOT_DIR - folder where to look for openssl. Set by pkg-config of brew by default.

License

Developed at Tinkoff.ru in 2020.
Distibuted under Apache License 2.0 LICENSE. You may also obtain this license at https://www.apache.org/licenses/LICENSE-2.0.

Contacts

Author - [email protected]
Current maintainer - [email protected]

Issues
  • wip: test

    wip: test

    PR Checklist

    Please check if your PR fulfills the following requirements:

    • [ ] The commit message follows Conventional Commits
    • [ ] Tests for the changes have been added (for bug fixes / features)
    • [ ] Docs have been added / updated (for bug fixes / features)

    PR Type

    What kind of change does this PR introduce?

    • [ ] Bugfix
    • [ ] Feature
    • [ ] Refactoring
    • [ ] Code style update
    • [ ] Build or CI related changes
    • [ ] Documentation content changes

    What is the current behavior?

    Closes #

    What is the new behavior?

    Does this PR introduce a breaking change?

    • [ ] Yes
    • [ ] No
    opened by i-vovk 1
  • ci: add codecov check on pull-requests

    ci: add codecov check on pull-requests

    • test: stabilize apple test case for send timeout
    • Increase data size, decrease timeout
    • chore: add pull request template
    • ci: cancel previous in-progress pull request job
    opened by i-vovk 1
  • wip: test

    wip: test

    PR Checklist

    Please check if your PR fulfills the following requirements:

    • [ ] The commit message follows Conventional Commits
    • [ ] Tests for the changes have been added (for bug fixes / features)
    • [ ] Docs have been added / updated (for bug fixes / features)

    PR Type

    What kind of change does this PR introduce?

    • [ ] Bugfix
    • [ ] Feature
    • [ ] Refactoring
    • [ ] Code style update
    • [ ] Build or CI related changes
    • [ ] Documentation content changes

    What is the current behavior?

    Closes #

    What is the new behavior?

    Does this PR introduce a breaking change?

    • [ ] Yes
    • [ ] No
    opened by i-vovk 0
  • [Bug] ConnectedEnv/2.ClosedReceive spontaneously fails

    [Bug] ConnectedEnv/2.ClosedReceive spontaneously fails

    Describe the bug SSL transmission may throw connection_reset error code.

    Steps to Reproduce https://travis-ci.com/TinkoffCreditSystems/stream-client/jobs/295070025

    Expected behavior Test passed

    Observed behavior

    /Users/travis/build/TinkoffCreditSystems/stream-client/test/transmission.cpp:117: Failure
    Value of: actual_ec == expected_err1 || actual_ec == expected_err2 || actual_ec == expected_err3
      Actual: false
    Expected: true
    Expected one of: [system:9] Bad file descriptor; [asio.misc:2] End of file; [asio.ssl.stream:1] stream truncated
             Actual: [system:54] Connection reset by peer
    

    Environment

    • OS (include version): macosx 10.13.6
    • Compiler (include version): AppleClang 9.1.0.9020039
    • Boost version: 1.66.0
    bug 
    opened by i-vovk 0
Releases(v1.4.1)
  • v1.4.1(Feb 22, 2022)

  • v1.4.0(Feb 17, 2022)

  • v1.3.0(Feb 16, 2022)

    Features

    • Support pool refill strategy and implement conservative and greedy (default) - (#20), (#24)

    Misc

    • cmake: Use system googletest library if found
    • cmake: Mute googletest warning
    • workflow: Check .ipp files with clang-format
    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Nov 24, 2021)

  • v1.1.14(Nov 23, 2021)

  • v1.1.13(Nov 17, 2021)

    Bug Fixes

    • connector: Fix data race for random generator
    • tests/timeout: Remove time check for zero timeout

    Misc

    • change googletest GIT_TAG to main
    • workflow: Explicitly install openssl with brew
    • readme: Add n.suboch to maintainers list
    Source code(tar.gz)
    Source code(zip)
  • v1.1.12(Sep 24, 2021)

  • v1.1.11(Aug 20, 2021)

  • v1.1.10(Aug 17, 2021)

  • v1.1.9(Jul 31, 2021)

    Features

    • connector::base_connection_pool: add try_get_session() method
    • connector::base_connection_pool: change global lock in watch_pool_routine() with several small locks
    Source code(tar.gz)
    Source code(zip)
  • v1.1.8(Jul 13, 2021)

  • v1.1.7(Jun 30, 2021)

  • v1.1.6(Jun 29, 2021)

  • v1.1.5(May 2, 2021)

  • v1.1.4(May 2, 2021)

  • v1.1.3(May 2, 2021)

    Bug Fixes

    • get_session(timeout_or_deadline) return invalid socket
    • Remove redundant ssl-handshake type parameter. Use client one

    Features

    • Add throwing get_session(timeout_or_deadline) function to the pool
    • Require standard openssl on macos (1.1+)
    • Add Apache 2.0 LICENSE file
    • Apply clang-format as code style guard
    • Add doxygen-format docs
    • Add IPv4/IPV6/Any selector to stream_client::resolver::base_resolver<>
    • Allow boost::asio::ip::basic_resolver_query::flags pass-through
    • Separate TCP/UDP implementation since they are based on boost::asio::basic_stream_socket/basic_datagram_socket
    • Add tests
    • Add readme

    Misc

    • Small README fixes
    • Style-related fixes
    Source code(tar.gz)
    Source code(zip)
Boost.GIL - Generic Image Library | Requires C++11 since Boost 1.68

Documentation GitHub Actions AppVeyor Azure Pipelines CircleCI Regression Codecov Boost.GIL Introduction Documentation Requirements Branches Community

Boost.org 145 Jun 17, 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
A single-header socket library for both Linux and Windows

COMS What is COMS? COMS is a single-header library designed to be simple to use. It supports TCP and UDP, Server and Client. Available for Windows and

null 5 Dec 23, 2021
C++ peer to peer library, built on the top of boost

Breep What is Breep? Breep is a c++ bridged peer to peer library. What does that mean? It means that even though the network is constructed as a peer

Lucas Lazare 111 Jun 28, 2022
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 Ultra fast and low latency asynchronous socket server & client C++ library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and

Ivan Shynkarenka 848 Jun 26, 2022
requests-like networking library using boost for C++

cq == C++ Requests cq == C++ Requests is a "Python Requests"-like C++ header-only library for sending HTTP requests. The library is inspired a lot by

null 11 Dec 15, 2021
Ole Christian Eidheim 738 Jul 2, 2022
Modern C++ socket library.

sockpp Simple, modern, C++ socket library. This is a fairly low-level C++ wrapper around the Berkeley sockets library using socket, acceptor, and conn

Frank Pagliughi 470 Jun 27, 2022
Packio - An asynchronous msgpack-RPC and JSON-RPC library built on top of Boost.Asio.

Header-only | JSON-RPC | msgpack-RPC | asio | coroutines This library requires C++17 and is designed as an extension to boost.asio. It will let you bu

Quentin Chateau 46 Jun 15, 2022
Socket and Networking Library using msgpack.org[C++11]

netLink C++ 11 KISS principle networking library. Features: C++ 11 IPv4, IPv6 Protocols: TCP, UDP Enable/Disable blocking mode Join/Leave UDP-Multicas

Alexander Meißner 208 May 29, 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.3k Jul 2, 2022
HTTP and WebSocket built on Boost.Asio in C++11

HTTP and WebSocket built on Boost.Asio in C++11 Branch Linux/OSX Windows Coverage Documentation Matrix master develop Contents Introduction Appearance

Boost.org 3.4k Jun 28, 2022
C++11 implementation of Socket.IO client

By virtue of being written in C++, this client works in several different platforms. The examples folder contains an iPhone, QT and Console example chat client! It depends on websocket++ and is inspired by socket.io-clientpp.

Socket.IO 1.9k Jun 27, 2022
HP-Socket bindings for aardio

HP-Socket-bindings-for-aardio HP-Socket is a high performance network framework. aardio is an extremely easy-to-use dynamic language, but it is also a

null 9 Jan 3, 2022
Simple server and client using python socket and declarative programming

Socket-programming Simple server and client using python socket and declarative programming How to use? open cmd and navigate to the location of the s

MAINAK CHAUDHURI 21 Sep 30, 2021
Asynchronous gRPC with Boost.Asio executors

asio-grpc This library provides an implementation of boost::asio::execution_context that dispatches work to a grpc::CompletionQueue. Making it possibl

Dennis 126 Jun 24, 2022
Small utility that leverages eBPF to dump the traffic of a unix domain socket

UnixDump UnixDump is a small eBPF powered utility that can be used to dump unix socket traffic. System requirements This project was developed on a Ub

Guillaume Fournier 5 Dec 1, 2021
Socket server for DAZ Studio meant for use with Streamdeck plug-in

StreamDeckSocket This listens on port 8080 of localhost. If the port is inconvenient, change it in "qhttpserver.h" as LISTEN_PORT do not change the LI

Stephen 2 Oct 9, 2021
As a Teaching Assistant, this is a sample project about socket programming for my teaching in a capstone course in NTUST(National Taiwan University of Science and Technology)

socket-programming As a Teaching Assistant, this is a sample project about socket programming for my teaching in a capstone course in NTUST(National T

Chang Wei 2 Oct 26, 2021