https://github.com/hackerl/asyncio
C++23 coroutine network framework
https://github.com/hackerl/asyncio
Last synced: 16 days ago
JSON representation
C++23 coroutine network framework
- Host: GitHub
- URL: https://github.com/hackerl/asyncio
- Owner: Hackerl
- License: apache-2.0
- Created: 2023-08-03T03:30:54.000Z (almost 2 years ago)
- Default Branch: master
- Last Pushed: 2025-04-12T04:16:21.000Z (3 months ago)
- Last Synced: 2025-04-13T09:12:03.857Z (3 months ago)
- Language: C++
- Homepage:
- Size: 682 KB
- Stars: 6
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[![Contributors][contributors-shield]][contributors-url]
[![Forks][forks-shield]][forks-url]
[![Stargazers][stars-shield]][stars-url]
[![Issues][issues-shield]][issues-url]
[![Apache 2.0 License][license-shield]][license-url]
asyncio
C++23 coroutine network framework
Explore the docs »
View Demo
·
Report Bug
·
Request Feature
Table of Contents
## About The Project
Based on the `libuv` event loop, use C++20 stackless `coroutines` to implement network components, and provide `channel` to send and receive data between tasks.
### Built With
* [![CMake][CMake]][CMake-url]
* [![vcpkg][vcpkg]][vcpkg-url]
* [![C++23][C++23]][C++23-url]## Getting Started
### Prerequisites
Required compiler:
* GCC >= 14
* LLVM >= 18
* MSVC >= 19.38Export environment variables:
* VCPKG_INSTALLATION_ROOT
* ANDROID_NDK_HOME(Android)### Build
* Linux
```sh
cmake -B build -DCMAKE_TOOLCHAIN_FILE="${VCPKG_INSTALLATION_ROOT}/scripts/buildsystems/vcpkg.cmake" && cmake --build build -j$(nproc)
```* Android
```sh
# set "ANDROID_PLATFORM" for dependencies installed by vcpkg: echo 'set(VCPKG_CMAKE_SYSTEM_VERSION 24)' >> "${VCPKG_INSTALLATION_ROOT}/triplets/community/arm64-android.cmake"
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)
```sh
cmake -B build -DCMAKE_TOOLCHAIN_FILE="$Env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" && cmake --build build -j $env:NUMBER_OF_PROCESSORS
```### Installation
Install `asyncio` from the [`vcpkg` private registry](https://github.com/Hackerl/vcpkg-registry):
1. Create a `vcpkg-configuration.json` file in the project root directory:
```json
{
"registries": [
{
"kind": "git",
"repository": "https://github.com/Hackerl/vcpkg-registry",
"baseline": "56e949885c4f22d5711523f360ac92d73f7a8495",
"packages": [
"asyncio",
"zero"
]
}
]
}
```> The `baseline` defines the minimum version of `asyncio` that will be installed. The one used above might be outdated, so please update it as necessary.
2. Create a `vcpkg.json` file in the project root directory:
```json
{
"name": "project name",
"version-string": "1.0.0",
"builtin-baseline": "9224b3bbd8df24999d85720b1d005dd6f969ade0",
"dependencies": [
"asyncio"
]
}
```3. Add the following to the `CMakeLists.txt` file:
```cmake
find_package(asyncio CONFIG REQUIRED)
target_link_libraries(custom_target PRIVATE asyncio::asyncio-main)
```## Usage
### HTTP Client
Using the `HTTP Client` in a `C++` project has never been easier:
```c++
#includeasyncio::task::Task asyncMain(const int argc, char *argv[]) {
const auto url = asyncio::http::URL::from("https://www.google.com");
CO_EXPECT(url);auto requests = asyncio::http::Requests::make();
CO_EXPECT(requests);auto response = co_await requests->get(*url);
CO_EXPECT(response);const auto content = co_await response->string();
CO_EXPECT(content);fmt::print("{}", *content);
co_return {};
}
```> We use `asyncMain` instead of `main` as the entry point, and `CO_EXPECT` is used to check for errors and throw them upwards.
### TCP
#### Server
```c++
#include
#include
#includeasyncio::task::Task handle(asyncio::net::TCPStream stream) {
const auto address = stream.remoteAddress();
CO_EXPECT(address);fmt::print("connection[{}]\n", *address);
while (true) {
std::string message;
message.resize(1024);const auto n = co_await stream.read(std::as_writable_bytes(std::span{message}));
CO_EXPECT(n);if (*n == 0)
break;message.resize(*n);
fmt::print("receive message: {}\n", message);
CO_EXPECT(co_await stream.writeAll(std::as_bytes(std::span{message})));
}co_return {};
}asyncio::task::Task serve(asyncio::net::TCPListener listener) {
std::expected result;
asyncio::task::TaskGroup group;while (true) {
auto stream = co_await listener.accept();if (!stream) {
result = std::unexpected{stream.error()};
break;
}auto task = handle(*std::move(stream));
group.add(task);
task.future().fail([](const auto &ec) {
fmt::print(stderr, "unhandled error: {} ({})\n", ec.message(), ec);
});
}co_await group;
co_return result;
}asyncio::task::Task asyncMain(const int argc, char *argv[]) {
zero::Cmdline cmdline;cmdline.add("host", "remote host");
cmdline.add("port", "remote port");cmdline.parse(argc, argv);
const auto host = cmdline.get("host");
const auto port = cmdline.get("port");auto listener = asyncio::net::TCPListener::listen(host, port);
CO_EXPECT(listener);auto signal = asyncio::Signal::make();
CO_EXPECT(signal);co_return co_await race(
serve(*std::move(listener)),
signal->on(SIGINT).transform([](const int) {
})
);
}
```> Start the server with `./server 127.0.0.1 8000`, and gracefully exit by pressing `ctrl + c` in the terminal.
#### Client
```c++
#include
#include
#includeasyncio::task::Task asyncMain(const int argc, char *argv[]) {
using namespace std::chrono_literals;
using namespace std::string_view_literals;zero::Cmdline cmdline;
cmdline.add("host", "remote host");
cmdline.add("port", "remote port");cmdline.parse(argc, argv);
const auto host = cmdline.get("host");
const auto port = cmdline.get("port");auto stream = co_await asyncio::net::TCPStream::connect(host, port);
CO_EXPECT(stream);while (true) {
CO_EXPECT(co_await stream->writeAll(std::as_bytes(std::span{"hello world"sv})));std::string message;
message.resize(1024);const auto n = co_await stream->read(std::as_writable_bytes(std::span{message}));
CO_EXPECT(n);if (*n == 0)
break;message.resize(*n);
fmt::print("receive message: {}\n", message);
co_await asyncio::sleep(1s);
}co_return {};
}
```> Connect to the server with `./client 127.0.0.1 8000`.
_For more examples, please refer to the [Documentation](https://github.com/Hackerl/asyncio/tree/master/doc)_
## Roadmap
- [ ] HTTP Server
See the [open issues](https://github.com/Hackerl/asyncio/issues) for a full list of proposed features (and known issues).
## Contributing
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!1. Fork the Project
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the Branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request## License
Distributed under the Apache 2.0 License. See `LICENSE` for more information.
## Contact
Hackerl - [@Hackerl](https://github.com/Hackerl) - [email protected]
Project Link: [https://github.com/Hackerl/asyncio](https://github.com/Hackerl/asyncio)
## Acknowledgments
* [libuv](https://libuv.org)
* [curl](https://curl.se)
* [treehh](https://github.com/kpeeters/tree.hh)
* [nlohmann-json](https://json.nlohmann.me)
* [OpenSSL](https://www.openssl.org)
* [Catch2](https://github.com/catchorg/Catch2)[contributors-shield]: https://img.shields.io/github/contributors/Hackerl/asyncio.svg?style=for-the-badge
[contributors-url]: https://github.com/Hackerl/asyncio/graphs/contributors
[forks-shield]: https://img.shields.io/github/forks/Hackerl/asyncio.svg?style=for-the-badge
[forks-url]: https://github.com/Hackerl/asyncio/network/members
[stars-shield]: https://img.shields.io/github/stars/Hackerl/asyncio.svg?style=for-the-badge
[stars-url]: https://github.com/Hackerl/asyncio/stargazers
[issues-shield]: https://img.shields.io/github/issues/Hackerl/asyncio.svg?style=for-the-badge
[issues-url]: https://github.com/Hackerl/asyncio/issues
[license-shield]: https://img.shields.io/github/license/Hackerl/asyncio.svg?style=for-the-badge
[license-url]: https://github.com/Hackerl/asyncio/blob/master/LICENSE
[CMake]: https://img.shields.io/badge/CMake-000000?style=for-the-badge&logo=cmake&logoColor=FF3E00
[CMake-url]: https://cmake.org
[vcpkg]: https://img.shields.io/badge/vcpkg-000000?style=for-the-badge&logo=v&logoColor=61DAFB
[vcpkg-url]: https://vcpkg.io
[C++23]: https://img.shields.io/badge/C++23-000000?style=for-the-badge&logo=cplusplus&logoColor=4FC08D
[C++23-url]: https://en.cppreference.com/w/cpp/20