Coproto is a flexible C++20 cross-platform protocol framework based on coroutines. The primary design goal of Coproto is to enable easy-to-write, high-performance protocols that can be run in any environment. Protocols are written in a synchronous manner (see below) but can be executed asynchronously across one or more threads. See the tutorials C++20, Custom Socket.
- Coroutine abstraction: Protocols can be written in a synchronous manner and evaluated in an asynchronous manner.
- Concurrent composition of multiple protocols: Multiple protocols can be concurrently executed on a single socket. Coproto ensures that each concurrent protocol receives the correct messages.
- Single or multi-threaded: A protocol can be executed on multiply threads while sharing a single socket. Coproto manages the logic required to ensure each thread/sub-protocol gets the correct messages.
- Local or network communication: Coproto does not mandate any particular socket type, e.g. posix, boost::asio, but instead allows the user to integrate their socket of choice. ALternatively, the included BufferingSocket allows the caller to get/set the next message for any protocol.
- Boost Asio and OpenSSL: The library can be built with Boost Asio TCP and OpenSSL TLS support.
- Test with network error injection: Test the robustness of the protocol by injecting networking errors or by modifying protocol messages.
C++20 Echo server example:
With C++20 the coroutine machinery can be used. Each socket operations can be co_awaited
which [possibly] pauses the current protocol and allows other work to be performed by the current thread, e.g. concurrently execute some other protocol. See the C++20 tutorial.
task<> echoClient(std::string message, Socket& socket) {
co_await socket.send(message);
co_await socket.recv(message);
}
task<> echoServer(Socket& socket) {
std::string message;
co_await socket.recvResize(message);
co_await socket.send(message);
}
void echoExample()
{
auto sockets = LocalAsyncSocket:makePair();
// lazily construct protocol objects
auto server = echoServer(sockets[0]);
auto client = echoClient("hello world", sockets[1]);
// Execute both protocols locally on the current thread.
sync_wait(when_all_ready(std::move(server), std::move(client)));
}
The library is cross-platform and has been tested on Windows, Mac, and Linux.
If it does not compile, please submit an issue with details.
CMake 3.15+ is required and the helper build script assumes python 3.
The library can be build directly via cmake or with the build.py
script.
Build the C++20 library with coroutines:
git clone ...
cd coproto
python3 build.py
The main executable with examples is frontend
and is located in the build directory, eg out/build/linux/frontend/frontend.exe, out/build/x64-Release/frontend/Release/frontend.exe
depending on the OS.
Various options can be set when building the library. These are set via cmake
or build.py
with -D OPTION=VALUE
syntax, e.g. -D COPROTO_FETCH_AUTO=true
.
COPROTO_FETCH_AUTO
: valuestrue,false
, automatically fetch dependencies if they are not found and needed. Defaults tofalse
for cmake andtrue
forbuild.py
.COPROTO_FETCH_SPAN
: valuestrue,false
, always fetch the span lite dependencies in C++14 mode.COPROTO_FETCH_MACORO
: valuestrue,false
, always fetch the macoro dependencies.COPROTO_FETCH_BOOST
: valuestrue,false
, always fetch the boost dependencies.
COPROTO_CPP_VER
: values14,17,20
, build with the desired c++ standard support.COPROTO_ENABLE_BOOST
: valuestrue,false
, build with boost asio support.COPROTO_ENABLE_OPENSSL
: valuestrue,false
, build with boost asio OpenSSL support.COPROTO_ENABLE_ASSERTS
: valuestrue,false
,build with optional asserts enabled.
The C++14 version requires span-line, optional-lite, variant-lite. Both C++14,C++20 versions depend on function2, macoro and optionally on Boost, OpenSSL. These dependencies can be managed via CMake
, the build.py
script or installed via an external tool. If an external tool is used install to system location or set -D CMAKE_PREFIX_PATH=path/to/install
. Using the python script, dependencies are automatically pulled based on need. This is achieved by defining the cmake variable FETCH_AUTO=ON
.
Coproto can be installed via cmake or as
python3 build.py --install
By default, the dependencies are not installed. To install them, run the corresponding --setup
command with the --install
flag.
By default, sudo is not used. If the installation requires sudo access, then add --sudo
to the build.py
script arguments.
Install location can be specified by --install==path/to/install
.
See python3 build.py --help
for full details.
coproto can be linked via cmake as
find_package(coproto REQUIRED)
target_link_libraries(myProject coproto::coproto)
To ensure that cmake can find coproto, you can either install coproto or build it locally and set -D CMAKE_PREFIX_PATH=path/to/coproto
or provide its location as a cmake HINTS
, i.e. find_package(coproto HINTS path/to/coproto)
.