C++20 coroutine network framework
Explore the docs »
View Demo
·
Report Bug
·
Request Feature
Table of Contents
Based on the libevent
event loop, use C++20 stackless coroutines
to implement events and network basic components, and provide channel
to send and receive data between tasks.
Due to many dependencies, it is not recommended to install manually, you should use vcpkg
.
Required compiler:
- GCC >= 13
- LLVM >= 16
- MSVC >= 19.38
Export environment variables:
- VCPKG_INSTALLATION_ROOT
- ANDROID_NDK_HOME(Android)
-
Linux
mkdir -p build && cmake -B build -DCMAKE_TOOLCHAIN_FILE="${VCPKG_INSTALLATION_ROOT}/scripts/buildsystems/vcpkg.cmake" && cmake --build build -j$(nproc)
-
Android
# set "ANDROID_PLATFORM" for dependencies installed by vcpkg: echo 'set(VCPKG_CMAKE_SYSTEM_VERSION 24)' >> "${VCPKG_INSTALLATION_ROOT}/triplets/community/arm64-android.cmake" mkdir -p build && cmake -B build -DCMAKE_TOOLCHAIN_FILE="${VCPKG_INSTALLATION_ROOT}/scripts/buildsystems/vcpkg.cmake" -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE="${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake" -DVCPKG_TARGET_TRIPLET=arm64-android -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-24 && cmake --build build -j$(nproc)
-
Windows(Developer PowerShell)
mkdir -p build && cmake -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" && cmake --build build -j $env:NUMBER_OF_PROCESSORS
You can use CMake
to compile and install based on the source code, or use CMake
+ vcpkg
directly.
-
CMakeLists.txt
find_package(asyncio CONFIG REQUIRED) add_executable(demo main.cpp) target_link_libraries(demo PRIVATE asyncio::asyncio)
-
vcpkg-configuration.json
{ "registries": [ { "kind": "git", "repository": "https://github.com/Hackerl/vcpkg-registry", "baseline": "4abdfe14cbaee3e51d28a169061b7d3e54dbcc37", "packages": [ "asyncio", "zero" ] } ] }
-
vcpkg.json
{ "name": "demo", "version-string": "1.0.0", "builtin-baseline": "c9e2aa851e987698519f58518aa16564af3a85ab", "dependencies": [ { "name": "asyncio", "version>=": "1.0.1" } ] }
-
Basic
asyncio::run([&]() -> asyncio::task::Task<void> { auto buffer = co_await asyncio::net::connect(host, port); if (!buffer) { LOG_ERROR("stream buffer connect failed{}]", buffer.error()); co_return; } while (true) { std::string message = "hello world\r\n"; auto result = co_await buffer->writeAll(std::as_bytes(std::span{message})); if (!result) { LOG_ERROR("stream buffer drain failed[{}]", result.error()); break; } auto line = co_await buffer->readLine(); if (!line) { LOG_ERROR("stream buffer read line failed[{}]", line.error()); break; } LOG_INFO("receive message[{}]", *line); co_await asyncio::sleep(1s); } });
-
TLS
asyncio::run([&]() -> asyncio::task::Task<void> { asyncio::net::ssl::Config config = { .insecure = insecure, .server = false }; if (ca) config.ca = *ca; if (cert) config.cert = *cert; if (privateKey) config.privateKey = *privateKey; auto context = asyncio::net::ssl::newContext(config); if (!context) { LOG_ERROR("create ssl context failed[{}]", context.error()); co_return; } auto buffer = co_await asyncio::net::ssl::connect(*context, host, port); if (!buffer) { LOG_ERROR("stream buffer connect failed[{}]", buffer.error()); co_return; } while (true) { std::string message = "hello world\r\n"; auto result = co_await buffer->writeAll(std::as_bytes(std::span{message})); if (!result) { LOG_ERROR("stream buffer drain failed[{}]", result.error()); break; } auto line = co_await buffer->readLine(); if (!line) { LOG_ERROR("stream buffer read line failed[{}]", line.error()); break; } LOG_INFO("receive message[{}]", *line); co_await asyncio::sleep(1s); } });
-
Basic
asyncio::run([]() -> asyncio::task::Task<void> { co_await asyncio::toThread([]() -> std::expected<void, std::error_code> { auto tp = std::chrono::system_clock::now(); std::this_thread::sleep_for(50ms); REQUIRE(std::chrono::system_clock::now() - tp > 50ms); return {}; }); });
-
Throw error
asyncio::run([]() -> asyncio::task::Task<void> { auto result = co_await asyncio::toThread([]() -> std::expected<void, std::error_code> { std::this_thread::sleep_for(10ms); return std::unexpected(make_error_code(std::errc::bad_message)); }); REQUIRE(!result); REQUIRE(result.error() == std::errc::bad_message); });
-
Basic
asyncio::run([]() -> asyncio::task::Task<void> { auto channel = asyncio::Channel<int>::make(100); co_await task::allSettled( [](auto channel) -> asyncio::task::Task<void, std::error_code> { std::expected<void, std::error_code> result; for (int i = 0; i < 1000; i++) { auto res = co_await channel->send(i); if (!res) { result = std::unexpected(res.error()); break; } co_await asyncio::sleep(1s); } co_return result; }(channel), [](auto channel) -> asyncio::task::Task<void, std::error_code> { std::expected<void, std::error_code> result; while (true) { auto res = co_await channel->receive(); if (!res) { result = std::unexpected(res.error()); break; } // do something } co_return result; }(channel) ); });
-
Concurrent
asyncio::run([]() -> asyncio::task::Task<void> { auto channel = asyncio::Channel<int>::make(100); co_await task::allSettled( [](auto channel) -> asyncio::task::Task<void, std::error_code> { std::expected<void, std::error_code> result; for (int i = 0; i < 1000; i++) { auto res = co_await channel->send(i); if (!res) { result = std::unexpected(res.error()); break; } co_await asyncio::sleep(1s); } co_return result; }(channel), asyncio::toThread([=]() -> std::expected<void, std::error_code> { std::expected<void, std::error_code> result; while (true) { auto res = channel->receiveSync(); if (!res) { result = std::unexpected(res.error()); break; } // do something that takes a long time } return result; }) ); });
For more examples, please refer to the Documentation
- HTTP WebSocket
- Asynchronous Filesystem
- Linux AIO
- Windows IOCP
- POSIX AIO
See the open issues for a full list of proposed features (and known issues).
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Distributed under the Apache 2.0 License. See LICENSE
for more information.
Hackerl - @Hackerl - [email protected]
Project Link: https://github.com/Hackerl/asyncio