Skip to content

rnburn/coevent

Repository files navigation

coevent

A C++ coroutine library for asynchronous networking. (Based off of libevent).

Quick Start

Make a simple echo server and client

// server

static coevent::detached_task process_session(coevent::socket socket) {
  std::array<char, 500> buffer;
  while (true) {
    co_await coevent::until_readable(socket);
    auto read_result = coevent::read(socket, {buffer.data(), buffer.size()});
    if (read_result.eof()) {
      co_return;
    }
    co_await coevent::write(socket, {buffer.data(), read_result.num_read()});
  }
}

static coevent::detached_task run_server(coevent::socket& listener_socket) {
  while (true) {
    auto socket = co_await accept(listener_socket);
    process_session(std::move(socket));
  }
}

int main() {
  coevent::io_context io_context;
  coevent::endpoint endpoint{"127.0.0.1", 8080};
  coevent::socket socket{io_context};
  socket.bind(endpoint);
  listen(socket, 10);
  run_server(socket);
  io_context.run();
  return 0;
}
// client

static coevent::task<void> random_sleep(coevent::io_context& io_context) {
  static thread_local std::mt19937 random_number_generator{std::random_device{}()};
  std::uniform_int_distribution distribution(0, 1000);
  co_await coevent::sleep(
      io_context,
      std::chrono::milliseconds{distribution(random_number_generator)});
}

static coevent::detached_task run_client(coevent::io_context& io_context, int index) {
  co_await random_sleep(io_context);

  coevent::socket socket{io_context, coevent::endpoint{"127.0.0.1", 8080}};

  auto send_message = "Hello from " + std::to_string(index);
  std::cout << "Sent: " << send_message << "\n";
  co_await coevent::write(socket, {send_message.data(), send_message.size()});

  std::string received_message(send_message.size(), ' ');
  co_await coevent::read(socket, {received_message.data(), received_message.size()});
  std::cout << "Received: " << received_message << "\n";
}

int main() {
  coevent::io_context io_context;
  for (int i=0; i<10; ++i) {
    run_client(io_context, i);
  }
  io_context.run();
  return 0;
}

See example/echo for the full example.

Installation

coevent requires libevent and a C++ compiler that supports coroutines. (Tested against clang-9).

$ mkdir .build
$ cd .build
# For clang use libc++ instead of libstdc++
$ cmake -DCMAKE_CXX_FLAGS="-stdlib=libc++" ..
$ make
$ sudo make install

The docker image rnburn/clang contains a version of clang suitable for building the library and the script ci/run_coevent_docker.sh can be used to spin up a docker environment that builds the project.

$ ./ci/run_coevent_docker.sh
# bazel build //...
# bazel test //...