Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 10 additions & 17 deletions doc/modules/ROOT/pages/3.tutorials/3a.echo-server.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,13 @@ class echo_server : public corosio::tcp_server
{
corosio::io_context& ctx_;
corosio::tcp_socket sock_;
std::string buf_;
char buf_[4096];

public:
explicit worker(corosio::io_context& ctx)
: ctx_(ctx)
, sock_(ctx)
{
buf_.reserve(4096);
}

corosio::tcp_socket& socket() override
Expand Down Expand Up @@ -98,22 +97,13 @@ capy::task<> echo_server::worker::do_session()
{
for (;;)
{
buf_.resize(4096);

// Read some data
auto [ec, n] = co_await sock_.read_some(
capy::mutable_buffer(buf_.data(), buf_.size()));

if (ec || n == 0)
break;

buf_.resize(n);
capy::mutable_buffer(buf_, sizeof buf_));

// Echo it back
auto [wec, wn] = co_await corosio::write(
sock_, capy::const_buffer(buf_.data(), buf_.size()));
sock_, capy::const_buffer(buf_, n));

if (wec)
if (wec || ec)
break;
}

Expand All @@ -124,7 +114,8 @@ capy::task<> echo_server::worker::do_session()
Notice:

* We reuse the worker's buffer across reads
* `read_some()` returns when _any_ data arrives
* `read_some()` returns when _any_ data arrives — it may deliver bytes alongside an error
* We always write before checking the error (advance-then-check); writing zero bytes is a no-op
* `corosio::write()` writes _all_ data (it's a composed operation)
* When the coroutine ends, the launcher returns the worker to the pool

Expand Down Expand Up @@ -215,12 +206,14 @@ For echo servers, we want complete message delivery.

=== Why Not Use Exceptions?

The session loop needs to handle EOF gracefully. Using structured bindings:
The session loop needs to handle EOF gracefully. Using structured bindings
with advance-then-check, we always act on `n` before inspecting `ec`:

[source,cpp]
----
auto [ec, n] = co_await sock.read_some(buf);
if (ec || n == 0)
auto [wec, wn] = co_await corosio::write(sock, const_buffer(buf.data(), n));
if (wec || ec)
break; // Normal termination path
----

Expand Down
19 changes: 4 additions & 15 deletions example/echo-server/echo_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

#include <cstdlib>
#include <iostream>
#include <string>

namespace corosio = boost::corosio;
namespace capy = boost::capy;
Expand All @@ -23,14 +22,13 @@ class echo_worker : public corosio::tcp_server::worker_base
{
corosio::io_context& ctx_;
corosio::tcp_socket sock_;
std::string buf_;
char buf_[4096];

public:
explicit echo_worker(corosio::io_context& ctx)
: ctx_(ctx)
, sock_(ctx)
{
buf_.reserve(4096);
}

corosio::tcp_socket& socket() override
Expand All @@ -47,22 +45,13 @@ class echo_worker : public corosio::tcp_server::worker_base
{
for (;;)
{
buf_.resize(4096);

// Read some data
auto [ec, n] = co_await sock_.read_some(
capy::mutable_buffer(buf_.data(), buf_.size()));

if (ec)
break;

buf_.resize(n);
capy::mutable_buffer(buf_, sizeof buf_));

// Echo it back
auto [wec, wn] = co_await capy::write(
sock_, capy::const_buffer(buf_.data(), buf_.size()));
sock_, capy::const_buffer(buf_, n));

if (wec)
if (wec || ec)
break;
}

Expand Down
3 changes: 1 addition & 2 deletions test/unit/tcp_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ class test_worker : public tcp_server::worker_base
char buf[64];
auto [ec, n] = co_await sock->read_some(
capy::mutable_buffer(buf, sizeof(buf)));
if (!ec)
(void)co_await sock->write_some(capy::const_buffer(buf, n));
(void)co_await sock->write_some(capy::const_buffer(buf, n));
sock->close();
}(&sock_));
}
Expand Down
Loading