Sockets
The socket class provides asynchronous TCP networking. It supports
connecting to servers, reading and writing data, and graceful connection
management.
| Code snippets assume: |
#include <boost/corosio/socket.hpp>
#include <boost/corosio/endpoint.hpp>
#include <boost/capy/buffers.hpp>
namespace corosio = boost::corosio;
namespace capy = boost::capy;
Overview
A socket represents one end of a TCP connection:
corosio::socket s(ioc);
s.open();
auto [ec] = co_await s.connect(
corosio::endpoint(boost::urls::ipv4_address::loopback(), 8080));
char buf[1024];
auto [read_ec, n] = co_await s.read_some(
capy::mutable_buffer(buf, sizeof(buf)));
Construction
Sockets are constructed from an execution context or executor:
// From io_context
corosio::socket s1(ioc);
// From executor
auto ex = ioc.get_executor();
corosio::socket s2(ex);
The socket doesn’t own system resources until open() is called.
Opening and Closing
open()
Creates the underlying TCP socket:
s.open(); // Creates IPv4 TCP socket, associates with IOCP
This allocates a socket handle and registers it with the I/O backend.
Throws std::system_error on failure.
Connecting
The connect() operation initiates a TCP connection:
auto [ec] = co_await s.connect(endpoint);
This returns an io_result<> that you can unpack with structured bindings.
Reading Data
read_some()
Reads available data:
char buf[1024];
auto [ec, n] = co_await s.read_some(
capy::mutable_buffer(buf, sizeof(buf)));
This completes when any data is available. The returned n may be less
than the buffer size.
End of Stream
When the peer closes the connection:
auto [ec, n] = co_await s.read_some(buf);
if (ec == capy::error::eof)
// Connection closed normally
if (n == 0 && !ec)
// Also indicates EOF in some cases
Reading Exact Amounts
Use the corosio::read() free function to fill a buffer completely:
auto [ec, n] = co_await corosio::read(s, buf);
// n == buffer_size(buf) or error occurred
See Composed Operations for details.
Writing Data
Cancellation
Move Semantics
Sockets are move-only:
corosio::socket s1(ioc);
corosio::socket s2 = std::move(s1); // OK
corosio::socket s3 = s2; // Error: deleted copy constructor
Move assignment closes any existing socket:
s1 = std::move(s2); // Closes s1's socket if open, then moves s2
| Source and destination must share the same execution context. |
The io_stream Interface
socket inherits from io_stream, which provides:
class io_stream : public io_object
{
public:
template<class MutableBufferSequence>
auto read_some(MutableBufferSequence const& buffers);
template<class ConstBufferSequence>
auto write_some(ConstBufferSequence const& buffers);
};
This enables polymorphic use:
capy::task<void> send_data(corosio::io_stream& stream)
{
co_await corosio::write(stream, some_buffer);
}
// Works with socket, wolfssl_stream, or any io_stream
corosio::socket sock(ioc);
co_await send_data(sock);
Buffer Sequences
Read and write operations accept buffer sequences:
// Single buffer
capy::mutable_buffer buf(data, size);
co_await s.read_some(buf);
// Multiple buffers (scatter/gather I/O)
std::array<capy::mutable_buffer, 2> bufs = {
capy::mutable_buffer(header, header_size),
capy::mutable_buffer(body, body_size)
};
co_await s.read_some(bufs);
See Buffer Sequences for details.
Thread Safety
| Operation | Thread Safety |
|---|---|
Distinct sockets |
Safe to use from different threads |
Same socket |
NOT safe for concurrent operations of the same type |
You can have one read and one write in flight simultaneously on the same socket. But don’t start two reads or two writes concurrently.
Example: Echo Client
capy::task<void> echo_client(corosio::io_context& ioc)
{
corosio::socket s(ioc);
s.open();
(co_await s.connect(
corosio::endpoint(boost::urls::ipv4_address::loopback(), 8080))).value();
std::string msg = "Hello, server!";
(co_await corosio::write(
s, capy::const_buffer(msg.data(), msg.size()))).value();
char buf[1024];
auto [ec, n] = co_await s.read_some(
capy::mutable_buffer(buf, sizeof(buf)));
if (!ec)
std::cout << "Server replied: "
<< std::string_view(buf, n) << "\n";
}
Next Steps
-
Acceptors — Accept incoming connections
-
Endpoints — IP addresses and ports
-
Composed Operations — read() and write()
-
Echo Server Tutorial — Server example