From 200974d9bee71514c7652af846f6196c7d33d867 Mon Sep 17 00:00:00 2001 From: Marcelo Zimbres Date: Sat, 2 Jul 2022 23:01:12 +0200 Subject: [PATCH] Adds an tcp echo server from libuv. --- Makefile.am | 4 +- .../cpp/{ => asio}/echo_server_client.cpp | 0 .../cpp/{ => asio}/echo_server_direct.cpp | 4 +- benchmarks/cpp/libuv/README.md | 7 ++ benchmarks/cpp/libuv/echo_server_direct.c | 87 +++++++++++++++++++ 5 files changed, 98 insertions(+), 4 deletions(-) rename benchmarks/cpp/{ => asio}/echo_server_client.cpp (100%) rename benchmarks/cpp/{ => asio}/echo_server_direct.cpp (93%) create mode 100644 benchmarks/cpp/libuv/README.md create mode 100644 benchmarks/cpp/libuv/echo_server_direct.c diff --git a/Makefile.am b/Makefile.am index bc9ae8c7..e2706fac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -46,8 +46,8 @@ if HAVE_CXX20 test_high_level_SOURCES = $(top_srcdir)/tests/high_level.cpp chat_room_SOURCES = $(top_srcdir)/examples/chat_room.cpp echo_server_SOURCES = $(top_srcdir)/examples/echo_server.cpp -echo_server_direct_SOURCES = $(top_srcdir)/benchmarks/cpp/echo_server_direct.cpp -echo_server_client_SOURCES = $(top_srcdir)/benchmarks/cpp/echo_server_client.cpp +echo_server_direct_SOURCES = $(top_srcdir)/benchmarks/cpp/asio/echo_server_direct.cpp +echo_server_client_SOURCES = $(top_srcdir)/benchmarks/cpp/asio/echo_server_client.cpp endif nobase_include_HEADERS =\ diff --git a/benchmarks/cpp/echo_server_client.cpp b/benchmarks/cpp/asio/echo_server_client.cpp similarity index 100% rename from benchmarks/cpp/echo_server_client.cpp rename to benchmarks/cpp/asio/echo_server_client.cpp diff --git a/benchmarks/cpp/echo_server_direct.cpp b/benchmarks/cpp/asio/echo_server_direct.cpp similarity index 93% rename from benchmarks/cpp/echo_server_direct.cpp rename to benchmarks/cpp/asio/echo_server_direct.cpp index d1664afd..c9592822 100644 --- a/benchmarks/cpp/echo_server_direct.cpp +++ b/benchmarks/cpp/asio/echo_server_direct.cpp @@ -29,7 +29,7 @@ awaitable echo(tcp::socket socket) co_await async_write(socket, net::buffer(data, n), use_awaitable); } } catch (std::exception const& e) { - std::printf("echo Exception: %s\n", e.what()); + //std::printf("echo Exception: %s\n", e.what()); } } @@ -49,7 +49,7 @@ int main() net::io_context io_context(1); co_spawn(io_context, listener(), detached); io_context.run(); - } catch (std::exception& e) { + } catch (std::exception const& e) { std::printf("Exception: %s\n", e.what()); } } diff --git a/benchmarks/cpp/libuv/README.md b/benchmarks/cpp/libuv/README.md new file mode 100644 index 00000000..e150f16b --- /dev/null +++ b/benchmarks/cpp/libuv/README.md @@ -0,0 +1,7 @@ +This example was taken from + + https://github.com/libuv/libuv/tree/v1.x/docs/code/tcp-echo-server + +To build it run, for example + + $ gcc echo_server_direct.c -luv -O2 -o echo_server_direct diff --git a/benchmarks/cpp/libuv/echo_server_direct.c b/benchmarks/cpp/libuv/echo_server_direct.c new file mode 100644 index 00000000..bd492462 --- /dev/null +++ b/benchmarks/cpp/libuv/echo_server_direct.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include + +#define DEFAULT_PORT 55555 +#define DEFAULT_BACKLOG 128 + +uv_loop_t *loop; +struct sockaddr_in addr; + +typedef struct { + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +void free_write_req(uv_write_t *req) { + write_req_t *wr = (write_req_t*) req; + free(wr->buf.base); + free(wr); +} + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { + buf->base = (char*) malloc(suggested_size); + buf->len = suggested_size; +} + +void on_close(uv_handle_t* handle) { + free(handle); +} + +void echo_write(uv_write_t *req, int status) { + if (status) { + fprintf(stderr, "Write error %s\n", uv_strerror(status)); + } + free_write_req(req); +} + +void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { + if (nread > 0) { + write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); + req->buf = uv_buf_init(buf->base, nread); + uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write); + return; + } + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, on_close); + } + + free(buf->base); +} + +void on_new_connection(uv_stream_t *server, int status) { + if (status < 0) { + fprintf(stderr, "New connection error %s\n", uv_strerror(status)); + // error! + return; + } + + uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t)); + uv_tcp_init(loop, client); + if (uv_accept(server, (uv_stream_t*) client) == 0) { + uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read); + } + else { + uv_close((uv_handle_t*) client, on_close); + } +} + +int main() { + loop = uv_default_loop(); + + uv_tcp_t server; + uv_tcp_init(loop, &server); + + uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &addr); + + uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0); + int r = uv_listen((uv_stream_t*) &server, DEFAULT_BACKLOG, on_new_connection); + if (r) { + fprintf(stderr, "Listen error %s\n", uv_strerror(r)); + return 1; + } + return uv_run(loop, UV_RUN_DEFAULT); +}