Skip to content

uchenily/uvio

Repository files navigation

uvio

GitHub License Static Badge Static Badge GitHub top language Actions Status Actions Status Actions Status

C++20 coroutines + libuv

示例

tcp echo server
#include "uvio/core.hpp"
#include "uvio/net.hpp"

using namespace uvio;
using namespace uvio::net;

// Ignore errors
auto process(TcpStream stream) -> Task<> {
    while (true) {
        std::array<char, 1024> buf{};

        if (auto ret = co_await stream.read(buf); !ret) {
            console.error(ret.error().message());
            break;
        }
        console.info("Received: `{}`", buf.data());
        if (auto ret = co_await stream.write(buf); !ret) {
            console.error(ret.error().message());
            break;
        }
    }
    co_return;
}

auto server() -> Task<> {
    std::string host{"0.0.0.0"};
    int         port{8000};

    auto listener = TcpListener();
    listener.bind(host, port);
    console.info("Listening on {}:{} ...", host, port);
    while (true) {
        auto stream = (co_await listener.accept()).value();
        spawn(process(std::move(stream)));
    }
}

auto main() -> int {
    block_on(server());
}
# 客户端
telnet localhost 8000
# 或者
nc localhost 8000 -v
http server
#include "uvio/net/http.hpp"

using namespace uvio::net::http;

auto main() -> int {
    HttpServer server{"0.0.0.0", 8000};
    server.add_route("/", [](const HttpRequest &req, HttpResponse &resp) {
        resp.body = std::format("{} {}\r\nhello", req.method, req.uri);
    });
    server.add_route("/test", [](const HttpRequest &req, HttpResponse &resp) {
        resp.body = std::format("{} {}\r\ntest route", req.method, req.uri);
    });
    server.run();
}
# 客户端
curl localhost:8000/ -v
websocket server/client
#include "uvio/net/http.hpp"
#include "uvio/net/websocket.hpp"

using namespace uvio::net::http;
using namespace uvio::net;

auto process_message(websocket::WebsocketFramed &channel) -> Task<> {
    // Ignore errors
    for (int i = 0; i < 64; i++) {
        auto msg = (co_await channel.recv()).value();
        LOG_INFO("Received: `{}`", std::string_view{msg.data(), msg.size()});

        co_await channel.send(msg);
    }
    co_await channel.close();
    co_return;
}

auto main() -> int {
    websocket::WebsocketServer server{"0.0.0.0", 8000};
    server.add_route("/", [](const HttpRequest &req, HttpResponse &resp) {
        resp.body = std::format("{} {}\r\nhello", req.method, req.uri);
    });
    server.handle_message(process_message);
    server.run();
}
#include "uvio/net/websocket.hpp"

using namespace uvio::net;
using namespace uvio;

auto process_message(websocket::WebsocketFramed &channel) -> Task<> {
    // Ignore errors
    for (int i = 0; i < 64; i++) {
        auto msg = std::format("test message {} from client", i);
        co_await channel.send(msg);

        auto msg2 = (co_await channel.recv()).value();
        LOG_INFO("Received: `{}`", std::string_view{msg2.data(), msg2.size()});
    }
    co_await channel.close();
    co_return;
}

auto main() -> int {
    websocket::WebsocketClient client{"127.0.0.1", 8000};
    client.handle_message(process_message);
    client.run();
}
socks5 server

完整代码请查看 socks5_server.cpp

auto main() -> int {
    socks5::Socks5Server proxy{"0.0.0.0", 1080};
    proxy.run();
}

在使用浏览器情况下, 可以安装 SwitchyOmega 插件测试

在终端下可以使用 curl 命令进行测试: curl -v http://www.baidu.com/ --proxy socks5://127.0.0.1:1080

功能

  • 异步TCP
  • 异步UDP
  • 异步DNS解析
  • 异步文件IO
  • 计时器
  • TTY
  • 管道
  • 信号处理
  • 子进程
  • 线程池
  • 同步原语

原始目标

  • 尝试复用基于回调的网络库(libuv)基础设施, 使用C++20协程做一层封装, 提供符合直觉的接口.
  • 探索能否实现以及实现的难易程度、两种方式实际使用上的对比.

开始

meson setup build
meson compile -C build

安装

meson install -C build [--destdir xxx_path]

或者直接拷贝目录:

cp -r uvio xxx_path

编译器版本

clang (>= 17) 或 gcc (>= 13) 或 apple clang (>= 15) 或 MSVC (>= 19)

基准测试

benchmark

参与开发

如果有使用上的疑问或者任何ideas, 欢迎通过 Issues 或者 Discussions 分享

致谢

项目设计与实现参考了以下开源项目, 在此表示感谢!

  • Zedio: A runtime for writing asychronous applications with Modern C++, based on C++20 coroutine and liburing (io-uring)
  • async_simple: Simple, light-weight and easy-to-use asynchronous components
  • ws28: C++17 WebSocket server library (uses libuv)