Last active
July 5, 2025 11:29
-
-
Save socketpair/913f4384fe3fea37b431a58943adbdaa to your computer and use it in GitHub Desktop.
Сегфолт от нейросети
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // echo_server.cpp – minimalist echo‑server using C++23 coroutines + io_uring // g++ -std=c++23 -Wall -O2 echo_server.cpp -luring -o echo_server | |
| #include <coroutine> #include <liburing.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <cstring> #include <cerrno> #include <system_error> #include <vector> #include <iostream> #include <memory> | |
| //--------------------------------------------------------------------- // Small RAII helpers ------------------------------------------------- //--------------------------------------------------------------------- class UniqueFd { int fd_ = -1; public: UniqueFd() = default; explicit UniqueFd(int fd) : fd_(fd) {} UniqueFd(const UniqueFd&) = delete; UniqueFd& operator=(const UniqueFd&) = delete; UniqueFd(UniqueFd&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } UniqueFd& operator=(UniqueFd&& other) noexcept { if (this != &other) { reset(); fd_ = other.fd_; other.fd_ = -1; } return *this; } ~UniqueFd() { reset(); } int get() const { return fd_; } int release() { int tmp = fd_; fd_ = -1; return tmp; } void reset(int fd = -1) { if (fd_ != -1) ::close(fd_); fd_ = fd; } explicit operator bool() const { return fd_ != -1; } }; | |
| //--------------------------------------------------------------------- // A very small coroutine/awaitable framework for io_uring ------------ //--------------------------------------------------------------------- struct IoContext; // fwd | |
| struct IoOperationBase { IoContext* ctx; // owning context std::coroutine_handle<> handle; // coroutine to resume int result = 0; // cqe->res will end up here }; | |
| struct IoContext { explicit IoContext(unsigned entries = 256) { if (io_uring_queue_init(entries, &ring, 0) != 0) { throw std::system_error(errno, std::system_category(), "io_uring_queue_init"); } } ~IoContext() { io_uring_queue_exit(&ring); } | |
| // submit & loop ----------------------------------------------------- void run() { while (!tasks.empty()) { io_uring_submit(&ring); io_uring_cqe* cqe; int ret = io_uring_wait_cqe(&ring, &cqe); if (ret < 0) throw std::system_error(-ret, std::system_category(), "io_uring_wait_cqe"); | |
| auto* op = reinterpret_cast<IoOperationBase*>(io_uring_cqe_get_data(cqe)); | |
| op->result = cqe->res; | |
| io_uring_cqe_seen(&ring, cqe); | |
| op->handle.resume(); | |
| } | |
| } | |
| template<typename T> void addTask(std::coroutine_handle<T> h) { tasks.push_back(h); } | |
| io_uring ring; std::vector<std::coroutine_handle<>> tasks; // keep root coroutines alive }; | |
| //--------------------------------------------------------------------- // Awaitables --------------------------------------------------------- //--------------------------------------------------------------------- struct AcceptAwaitable : IoOperationBase { int listen_fd; sockaddr_in* addr; socklen_t* addrlen; | |
| bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle<> h) { handle = h; io_uring_sqe* sqe = io_uring_get_sqe(&ctx->ring); if (!sqe) throw std::runtime_error("get_sqe failed"); io_uring_prep_accept(sqe, listen_fd, reinterpret_cast<sockaddr*>(addr), addrlen, 0); io_uring_sqe_set_data(sqe, this); } int await_resume() { if (result < 0) throw std::system_error(-result, std::system_category(), "accept"); return result; } }; | |
| struct RecvAwaitable : IoOperationBase { int fd; void* buf; size_t len; | |
| bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle<> h) { handle = h; io_uring_sqe* sqe = io_uring_get_sqe(&ctx->ring); if (!sqe) throw std::runtime_error("get_sqe failed"); io_uring_prep_recv(sqe, fd, buf, len, 0); io_uring_sqe_set_data(sqe, this); } int await_resume() { if (result < 0) throw std::system_error(-result, std::system_category(), "recv"); return result; } }; | |
| struct SendAwaitable : IoOperationBase { int fd; const void* buf; size_t len; | |
| bool await_ready() const noexcept { return false; } void await_suspend(std::coroutine_handle<> h) { handle = h; io_uring_sqe* sqe = io_uring_get_sqe(&ctx->ring); if (!sqe) throw std::runtime_error("get_sqe failed"); io_uring_prep_send(sqe, fd, buf, len, MSG_NOSIGNAL); io_uring_sqe_set_data(sqe, this); } int await_resume() { if (result < 0) throw std::system_error(-result, std::system_category(), "send"); return result; } }; | |
| //--------------------------------------------------------------------- // Task type ---------------------------------------------------------- //--------------------------------------------------------------------- struct Task { struct promise_type { Task get_return_object() { return Task(std::coroutine_handle<promise_type>::from_promise(*this)); } std::suspend_always initial_suspend() noexcept { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() { std::terminate(); } }; | |
| explicit Task(std::coroutine_handle<promise_type> h) : handle(h) {} Task(const Task&) = delete; Task(Task&&) noexcept = default; ~Task() { if (handle) handle.destroy(); } | |
| void start(IoContext& ctx) { ctx.addTask(handle); handle.resume(); } | |
| private: std::coroutine_handle<promise_type> handle; }; | |
| //--------------------------------------------------------------------- // Echo session ------------------------------------------------------- //--------------------------------------------------------------------- Task echo_session(IoContext& ctx, int client_fd) { UniqueFd sock{client_fd}; constexpr size_t BUF_SIZE = 4096; char buffer[BUF_SIZE]; | |
| while (true) { int n = co_await RecvAwaitable{&ctx, {}, 0, sock.get(), buffer, BUF_SIZE}; if (n == 0) break; // client closed co_await SendAwaitable{&ctx, {}, 0, sock.get(), buffer, static_cast<size_t>(n)}; } } | |
| //--------------------------------------------------------------------- // Accept loop -------------------------------------------------------- //--------------------------------------------------------------------- Task accept_loop(IoContext& ctx, int listen_fd) { while (true) { sockaddr_in addr; socklen_t len = sizeof(addr); int client = co_await AcceptAwaitable{&ctx, {}, 0, listen_fd, &addr, &len}; echo_session(ctx, client).start(ctx); } } | |
| //--------------------------------------------------------------------- // Setup listening socket -------------------------------------------- //--------------------------------------------------------------------- UniqueFd make_listen_socket(uint16_t port) { int fd = ::socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) throw std::system_error(errno, std::system_category(), "socket"); UniqueFd sock{fd}; | |
| int opt = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) throw std::system_error(errno, std::system_category(), "setsockopt"); | |
| sockaddr_in addr{}; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(port); if (bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) throw std::system_error(errno, std::system_category(), "bind"); if (listen(fd, SOMAXCONN) < 0) throw std::system_error(errno, std::system_category(), "listen"); | |
| return sock; } | |
| //--------------------------------------------------------------------- // main --------------------------------------------------------------- //--------------------------------------------------------------------- int main(int argc, char* argv[]) { uint16_t port = 12345; if (argc > 1) port = static_cast<uint16_t>(std::stoi(argv[1])); | |
| try { UniqueFd listen_fd = make_listen_socket(port); IoContext ctx; accept_loop(ctx, listen_fd.get()).start(ctx); std::cout << "Echo‑server listening on port " << port << "...\n"; ctx.run(); } catch (const std::exception& ex) { std::cerr << "Fatal: " << ex.what() << "\n"; return 1; } return 0; } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment