Skip to content

Commit

Permalink
Add TCP echo server
Browse files Browse the repository at this point in the history
  • Loading branch information
longhao-li committed Sep 10, 2024
1 parent b3417a5 commit ba6772d
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 0 deletions.
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ endif()
option(NYAIO_BUILD_SHARED_LIBS "Build nyaio as shared library. The CMake BUILD_SHARED_LIBS option does not affect this project." OFF)
option(NYAIO_WARNINGS_AS_ERRORS "Treat warnings as errors when building nyaio." OFF)
option(NYAIO_BUILD_TESTS "Build tests for nyaio." OFF)
option(NYAIO_BUILD_EXAMPLES "Build examples for nyaio." OFF)
option(NYAIO_ENABLE_LTO "Enable link-time optimization for shared library. Ignored for static library." OFF)

file(GLOB_RECURSE NYAIO_HEADER_FILES "include/nyaio/*.hpp")
Expand Down Expand Up @@ -147,3 +148,8 @@ if(NYAIO_BUILD_TESTS)
include(${doctest_SOURCE_DIR}/scripts/cmake/doctest.cmake)
doctest_discover_tests(nyaio-test)
endif()

# Build examples.
if(NYAIO_BUILD_EXAMPLES)
add_subdirectory(example)
endif()
3 changes: 3 additions & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# TCP echo server.
add_executable(echo "echo/main.cpp")
target_link_libraries(echo PRIVATE nyaio::nyaio)
89 changes: 89 additions & 0 deletions example/echo/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include "nyaio/io.hpp"

#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace nyaio;

namespace {

auto echo(TcpStream stream) noexcept -> Task<> {
char buffer[4096];
while (true) {
auto [bytes, error] = co_await stream.receiveAsync(buffer, sizeof(buffer));

// Handle error.
if (error != std::errc{}) [[unlikely]] {
std::fprintf(stderr, "stream receive error: %s\n",
std::strerror(static_cast<int>(error)));
break;
}

// Connection closed.
if (bytes == 0) [[unlikely]]
break;

// Send received data back.
std::uint32_t totalSent = 0;
while (totalSent < bytes) {
auto [sent, error] = co_await stream.sendAsync(buffer + totalSent, bytes - totalSent);

// Handle error.
if (error != std::errc{}) [[unlikely]] {
std::fprintf(stderr, "stream send error: %s\n",
std::strerror(static_cast<int>(error)));
co_return;
}

totalSent += sent;
}
}
}

auto listener(const InetAddress &address) noexcept -> Task<> {
// Bind server to the address.
TcpServer server;
std::errc error = server.bind(address);
if (error != std::errc{}) [[unlikely]] {
std::fprintf(stderr, "server bind error: %s\n", std::strerror(static_cast<int>(error)));
std::terminate();
}

// Listen for incoming connections.
while (true) {
auto [stream, error] = co_await server.acceptAsync();

// Handle error.
if (error != std::errc{}) [[unlikely]] {
std::fprintf(stderr, "server accept error: %s\n",
std::strerror(static_cast<int>(error)));
continue;
}

// Schedule new connection in worker. Listener does not care about result of the connection.
co_await ScheduleAwaitable(echo(std::move(stream)));
}
}

} // namespace

auto main(int argc, char **argv) -> int {
if (argc != 3) {
std::fprintf(stderr, "Usage: %s <address> <port>\n", argv[0]);
return EXIT_FAILURE;
}

// FIXME: may throw exception.
IpAddress address(argv[1]);
std::uint16_t port = std::atoi(argv[2]);
InetAddress addr(address, port);

IoContext ctx;
ctx.dispatch(listener, addr);

// Actually noreturn here.
ctx.run();

return 0;
}

0 comments on commit ba6772d

Please sign in to comment.