{"id":13415559,"url":"https://github.com/xuanyi-fu/xynet","last_synced_at":"2025-03-14T23:30:50.966Z","repository":{"id":163607736,"uuid":"260076160","full_name":"xuanyi-fu/xynet","owner":"xuanyi-fu","description":"network library based on io_uring and C++20 coroutine","archived":false,"fork":false,"pushed_at":"2020-05-26T03:17:18.000Z","size":193,"stargazers_count":100,"open_issues_count":2,"forks_count":14,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-07-31T21:54:05.013Z","etag":null,"topics":["coroutine","cpp20","io-uring","iouring","liburing","network-library"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xuanyi-fu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-04-30T00:25:55.000Z","updated_at":"2024-06-26T05:44:46.000Z","dependencies_parsed_at":"2024-01-15T23:38:18.692Z","dependency_job_id":null,"html_url":"https://github.com/xuanyi-fu/xynet","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xuanyi-fu%2Fxynet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xuanyi-fu%2Fxynet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xuanyi-fu%2Fxynet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xuanyi-fu%2Fxynet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xuanyi-fu","download_url":"https://codeload.github.com/xuanyi-fu/xynet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243663252,"owners_count":20327299,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["coroutine","cpp20","io-uring","iouring","liburing","network-library"],"created_at":"2024-07-30T21:00:50.289Z","updated_at":"2025-03-14T23:30:50.676Z","avatar_url":"https://github.com/xuanyi-fu.png","language":"C++","funding_links":[],"categories":["C/C++"],"sub_categories":[],"readme":"xynet\n=====\nExperimental C++ network library based on io_uring and coroutine. This project is developed for understanding and practice C++20 new features(ranges, coroutine) and new Linux I/O API io_uring.  \n\nFeatures\n-----\n\n- Header only\n- Based on io_uring, the new Linux asynchronous I/O API\n- Based on C++20 coroutine\n- [`file_descriptor`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/file_descriptor.h) is designed in the CRTP Mixin pattern, all operations(recv, send, listen...) are modularized and thus optional.\n- [`buffer_sequence`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/buffer.h) is designed to be compatible with C++20 [`std::span`](https://en.cppreference.com/w/cpp/header/span)\n- like C++17 [`\u003cfilesystem\u003e`](https://en.cppreference.com/w/cpp/header/filesystem), support error handling in both `std::error_code` and exception\n- coroutine part is based on Lewis Baker's [cppcoro](https://github.com/lewissbaker/cppcoro), modified so that it could compile using gcc10.\n- Efficient:\n  - Few dynamic allocation: most of the allocations are for the coroutine stack itself.\n  - Few system calls compared with epoll based libraries: All asynchronous operations are submitted and reaped through io_uring by a single system call.\n  \nRequirements\n-----\n\n- Compiler: GCC10.0.1 (or later)\n- Linux Kernel: 5.2 (or later)\n- [Liburing](https://www.github.com/axboe/liburing): 0.5(or later)\n- OpenSSL: for the SHA-1 in websocket(will be removed later)\n\nExample\n-----\n\n- [RFC864 Character Generator Protocol](https://tools.ietf.org/html/rfc864): [chargen.cpp](https://github.com/xuanyi-fu/xynet/blob/master/example/simple/chargen.cpp)\n- [RFC867 Daytime Protocol](https://tools.ietf.org/html/rfc867): [daytime.cpp](https://github.com/xuanyi-fu/xynet/blob/master/example/simple/daytime.cpp)\n- [RFC863 Discard Protocol](https://tools.ietf.org/html/rfc863): [discard.cpp](https://github.com/xuanyi-fu/xynet/blob/master/example/simple/discard.cpp)\n- [RFC862 Echo Protocol](https://tools.ietf.org/html/rfc862): [echo.cpp](https://github.com/xuanyi-fu/xynet/blob/master/example/simple/echo.cpp)\n- [RFC868 Time Protocol](https://tools.ietf.org/html/rfc862): [time.cpp](https://github.com/xuanyi-fu/xynet/blob/master/example/simple/time.cpp)\n- boost::asio ping-pong performance test: [pingpong](https://github.com/xuanyi-fu/xynet/tree/master/example/pingpong)\n- [ttcp](https://en.wikipedia.org/wiki/Ttcp): [ttcp](https://github.com/xuanyi-fu/xynet/tree/master/example/ttcp)\n- boost::asio chatroom: [chat](https://github.com/xuanyi-fu/xynet/tree/master/example/chat)\n- websocket discard: [websocket_discard.cpp](https://github.com/xuanyi-fu/xynet/blob/master/example/websocket/websocket_discard.cpp)\n- websocket echo: [websocket_echo.cpp](https://github.com/xuanyi-fu/xynet/blob/master/example/websocket/websocket_echo.cpp)\n- [boost::beast websocket chatroom](https://www.boost.org/doc/libs/1_70_0/libs/beast/doc/html/beast/examples.html#beast.examples.chat_server): [websocket_chat.cpp](https://github.com/xuanyi-fu/xynet/blob/master/example/websocket/websocket_chat.cpp)\n\nUsage\n-----\n- `file_descriptor`\n\n  ```cpp\n  template \u003ctemplate \u003ctypename...\u003e typename ... Modules\u003e\n  class file_descriptor\u003cdetail::module_list\u003cModules ...\u003e\u003e\n    : public file_descriptor_base\n    , public Modules\u003cfile_descriptor\u003cdetail::module_list\u003cModules ...\u003e\u003e\u003e...\n  {};\n  ```\n\n  `file_descriptor` is a handler that has unique ownership of file descriptor, like `std::unique_ptr`.\n    - move-only, \n    - RAII. [`::close()`](http://man7.org/linux/man-pages/man2/close.2.html) is called in its destructor if the underlying file descriptor is valid.\n    - Modularized: `Modules` are interfaces that are mixin'ed into the base class. `Modules` access `file_descriptor` by static polymorphism, i.e. cast `this` into the base class type.\n    - default constructor will initialize the underlying file descriptor to be an invalid one.\n    - Mixin'ed modules use `set()` and `get()` to work with the file_descriptor. \n\n- `socket_t`\n\n  ```cpp\n  using socket_t = file_descriptor\n  \u003c\n    detail::module_list\n    \u003c\n      socket_init,\n      address,\n      operation_shutdown,\n      operation_set_options,\n      operation_bind,\n      operation_listen,\n      operation_accept,\n      operation_connect,\n      operation_send,\n      operation_recv,\n      operation_close\n    \u003e\n  \u003e;\n  ```\n\n  convenient type alias that has all modules for socket. You can define you own type alias. For example, an acceptor does not need to do send or recv.\n\n  ```cpp\n  using acceptor_t = file_descriptor\n  \u003c\n    detail::module_list\n    \u003c\n      socket_init,\n      operation_set_options,\n      operation_bind,\n      operation_listen,\n      operation_accept\n    \u003e\n  \u003e;\n  ```\n\n- `buffer_sequence` and `const_buffer_sequence`\n\n  `buffer_sequence` takes a sequences of Containers which satisfy the concept [`std::ranges::contiguous_range`](https://en.cppreference.com/w/cpp/ranges/contiguous_range) then transform them into [iovec](http://man7.org/linux/man-pages/man2/readv.2.html).\n\n  `buffer_sequence` could be constructed using:\n  \n  ```cpp\n  template\u003ctypename... Containers\u003e\n  buffer_sequence(Containers\u0026\u0026... containers)\n  ```\n  where `Containers` could be \n    - `std::span\u003cstd::byte, size or std::dynamic_extent\u003e`\n    - `std::span\u003cTs, size or std::dynamic_extent\u003e`\n    - contiguous ranges that are writable\n\n  or \n\n  ```cpp\n  template\u003ctypename BufferRange\u003e\n  requires std::ranges::viewable_range\u003cBufferRange\u0026\u003e\n           \u0026\u0026 std::ranges::contiguous_range\u003cstd::ranges::range_value_t\u003cBufferRange\u003e\u003e\n  buffer_sequence(BufferRange\u0026 buffer_range)\n  ```\n\n  where `BufferRange` is a range of contiguous ranges. Notice that, different from the former one, `iovec`s are stored in a `std::vector` where dynamic allocation is inevitable.\n\n- Modules \n\n  All modules support error handling by \n    - `std::error_code`: by passing an lvalue reference of `std::error_code` (like C++17 [`\u003cfilesystem\u003e`](https://en.cppreference.com/w/cpp/header/filesystem)), should there be an error, the lvalue reference passed will assign with a new error_code, otherwise, it will be [`clear()`](https://en.cppreference.com/w/cpp/error/error_code/clear).\n\n    - `exception`. An [`std::system_error`](https://en.cppreference.com/w/cpp/header/system_error) constructed by the reason encapsulated in a `std::error_code` will be throwed if there is an error.\n\n  - [`socket_init`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/socket/impl/socket_init.h)\n\n    - `init()`, `init(std::erro_code\u0026 error)` create a IPv4/TCP socket and set the `file_descriptor` with the file_descriptor returned form [`::socket()`](http://man7.org/linux/man-pages/man2/socket.2.html).\n  \n  - [`address`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/socket/impl/address.h)\n\n    the size of `file_descriptor` will increase if this module is used.\n\n    Getters and setters are provided: `set_local_address(const socket_address\u0026 address)`, `set_peer_address(const socket_address\u0026 address)`, `get_local_address()`, `get_peer_address()`.\n    Moudles like `operation_accept`, `operation_connect` , will set the `address` on success. \n\n\n  synchronous operation modules\n\n  - [`operation_shutdown`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/socket/impl/shutdown.h)\n\n    `shutdown(int how = SHUTWR)`, `shutdown(int how, std::error_code\u0026 error)`, `shutdown(std::error_code\u0026 error)`\n\n  - [`operation_bind`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/socket/impl/bind.h)\n\n    bind the socket to a given address. If module [`address`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/socket/impl/address.h) is used, set the local address on success. If `bind` with `socket_address{0}`, then a random port will be assigned and the local address will also be set on success.\n\n    `bind(const socket_address\u0026 address)`, `bind(const socket_address\u0026 address, std::error_code\u0026 error)` \n\n  - [`operation_set_options`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/socket/impl/setsockopt.h)\n\n    call `::setsockopt`.\n\n    `void setsockopt(int level, int optname, const void* optval, socklen_t optlen, std::error_code\u0026 error)`, `void setsockopt(int level, int optname, const void* optval, socklen_t optlen)`,\n    `void reuse_address(std::error_code\u0026 error)`,\n    `void reuse_address()`\n\n  - [`operation_listen`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/socket/impl/listen.h)\n\n    put the socket into listen state\n    `listen(int backlog = SOMAXCONN)`, `listen(int backlog, std::error_code\u0026 error)`, `listen(std::error_code\u0026 error)`.\n\n  asynchronous operation modules\n\n  all asynchronous operations provides an optional argument `duration` to impose a timeout.\n\n  - [`operation_accept`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/socket/impl/accept.h)\n\n  ```cpp\n  template\u003ctypename F2, typename... Args\u003e [[nodiscard]]\n  decltype(auto) accept(F2\u0026 peer_socket, Args\u0026\u0026... args) noexcept\n  ```\n\n    - `peer_socket` The socket into which the new connection will be accpeted.\n\n      1. Args is void: \n      The awaiter returned by the function will throw exception to report the error.\n      A std::system_error constructed with the corresponding std::error_code will be \n      throwed if the accept operation is failed after being co_await'ed.\n      2. Args is a Duration, i.e. std::chrono::duration\u003cRep, Period\u003e. \n      This duration will be treated as the timeout for the operation. If the operation \n      does not finish within the given duration, the operation will be canneled and an error_code\n        (std::errc::operation_canceled) will be returned. \n        \n      3. Args is an lvalue reference of a std::error_code\n      The awaiter returned by the function will use std::error_code to report the error.\n      Should there be an error in the operation, the std::error_code passed by lvalue reference will \n      be reset. Otherwise, it will be clear.\n    \n      4. Args are first a Duration, second an lvalue reference of a std::error_code\n      The operation will have the features described in 2 and 3.\n  \n  - [`operation_connect`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/socket/impl/connect.h)\n\n  ```cpp\n  template\u003ctypename... Args\u003e [[nodiscard]]\n  decltype(auto) connect(const socket_address\u0026 address, Args\u0026\u0026... args) noexcept\n  ```\n\n  `address`: the address with which the connection will be established.\n  `args`: same as `args` desribed in `operation_accept`\n\n  - [`operation_close`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/socket/impl/close.h)\n\n  This operation will read from the socket until it reads a 0(eof). Then it will call close(2) on the socket.\n\n  ```cpp\n  template\u003ctypename... Args\u003e\n  [[nodiscard]]\n  decltype(auto) close(Args\u0026\u0026... args) noexcept \n  ```\n\n  `args`: same as `args` desribed in `operation_accept`\n\n  - [`operation_recv`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/socket/impl/recv_all.h)\n\n    `recv([std::error_code\u0026 error], [Duration\u0026\u0026 duration], Args\u0026\u0026... args)`\n    where `args` will be forwarded to the constructor of `buffer_sequence`.\n\n    - The buffers will be filled with the same order as the order they were in the lvalue reference  of a viewable range or the order they were in args. \n    - The operation will finish if there is an error(including the socket reads EOF) or all the buffers are filled. That is, it may use recvmsg(2) more than once.\n    - After the operation is co_await'ed and then finishes, it will return the bytes transferred.\n\n    `recv_some([std::error_code\u0026 error], [Duration\u0026\u0026 duration], Args\u0026\u0026... args)`\n    where `args` will be forwarded to the constructor of `buffer_sequence`.\n\n    this awaiter will resume the coroutine after the first recv operation finished, regardless of whether the buffers are filled up or not.\n\n  - [`operation_send`](https://github.com/xuanyi-fu/xynet/blob/master/include/xynet/socket/impl/send_all.h)\n\n    `recv([std::error_code\u0026 error], [Duration\u0026\u0026 duration], Args\u0026\u0026... args)`\n     where `args` will be forwarded to the constructor of `const_buffer_sequence`","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxuanyi-fu%2Fxynet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxuanyi-fu%2Fxynet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxuanyi-fu%2Fxynet/lists"}