tcp_stream
The tcp_stream
represents the a duplex network stream for writing and reading data. read
, shutdown
and cancel
are not thread safe. Deconstruction or moving the tcp_stream
while in use results in undefined behavior. A user should make sure to ensure to shutdown
and wait for any operations to leave the functions before deconstructing the object.
async_function<>
your_class::run_stream(tcp_stream&& _stream)
{
/* Save locally so doesnt go out of scope when we suspend */
tcp_stream stream(std::move(_stream));
auto data_to_send = "hello world";
std::size_t written = co_await stream.Write(data_to_send);
if (written == ::strlen(data_to_send)) {
/* Get 1 byte back as confirmation */
auto buffer_opt = co_await stream.Read(1);
/* Read can return less then requested but not more... */
if (buffer_opt && buffer_opt->size()) {
std::cout << "Received: " << buffer_opt.at(0) << "\n";
}
}
/* Ensure we shut it down! (flushes all writes and wakes any readers) */
co_await stream.shut_down();
/* RAII will clean up for us! */
}
-
template<MemoryType DataType = std::byte>
class zab::tcp_stream This class represents the a duplex network stream for writing and reading data.
- Template Parameters
DataType – The MemoryType this stream reads and writes.
Public Types
-
using net_op = network_operation::net_op
Public Functions
-
inline tcp_stream()
Construct a tcp stream object in an empty state.
Using this object from this constructor is undefined behaviour unless you are writing to it via a swap, a move or move assignment.
-
inline tcp_stream(engine *_engine, int _fd)
Construct a new tcp stream object associated with a engine and an socket descriptor.
This interface assumes the socket was created in blocking mode.
- Parameters
_engine – The engine to used.
_fd – The socket to used.
-
tcp_stream(const tcp_stream&) = delete
There is no copy constructor for a tcp_stream.
-
inline tcp_stream(tcp_stream &&_move)
Construct a new tcp stream object by swapping the resources owned by _move.
- Parameters
_move – The tcp stream to move.
-
inline ~tcp_stream()
Destroy the tcp stream object.
It is far more efficient to manually shutdown, cancel reads and writes and close the socket before the object is deconstructed. Failure to do so will spawn background fibres to do this in the background.
We first try to cancel any pending writes in the background. The clear any errors from the socket.
The deconstruction of net_op_ will cancel any pending reads and close the socket in the background.
-
inline tcp_stream &operator=(tcp_stream &&tcp_stream)
Move operator for a tcp stream. This will just swap to two streams.
- Parameters
tcp_stream – The stream to swap.
- Returns
tcp_stream& this.
-
inline int descriptor() const noexcept
Get the underlying socket descriptor.
- Returns
int
-
inline int last_error() noexcept
Get the last error.
This clears the error.
- Returns
int
-
inline void set_error(int _error) noexcept
Set the error for the stream.
- Parameters
_error – The error to set for the stream.
-
inline auto cancel_read() noexcept
Attempt to cancel the current read operation.
This function only suspends if there is a pending read operation.
@co_return void Resumes after cancelation.
-
inline auto cancel_write() noexcept
Attempt to cancel the current write operation.
This function only suspends if there is a pending write operation.
@co_return void Resumes after cancelation.
-
inline auto close() noexcept
Attempt to close the socket.
This function only suspends if there is a socket to close.
@co_return true The socket was successfully closed. @co_return false The socket failed to close.
-
inline simple_future shutdown() noexcept
Shutdown the stream by cancelling any pending operations and signalling shutdown.
@co_return void on shutdown completion.
-
inline auto read_some(std::span<DataType> _data, size_t _offset = 0, int _flags = 0) noexcept
Attempt to read up to
_data.size() - _offset
bytes into the span at the given offset.If _data.size() - _offset is larger then kMaxRead, then kMaxRead is used as the max.
- Parameters
_data – The buffer to read into.
_offset – The offset from where to start reading in.
_flags – Any flags to pass to recv. @co_return int The amount of bytes read or -1 if an error occurred.
-
inline auto read(std::span<DataType> _data, size_t _offset = 0, int _flags = 0) noexcept
Attempts to
_data.size() - _offset
bytes into the span at the given offset. Blocks until the amount is read, a signal interupts the call or an error occurs.If _data.size() - _offset is larger then kMaxRead, then kMaxRead is used as the max.
- Parameters
_data – The buffer to read into.
_offset – The offset from where to start reading in.
_flags – Any flags to pass to recv. @co_return long long The amount of bytes read.
-
inline auto write_some(std::span<const DataType> _data, size_t _offset = 0, int _flags = MSG_NOSIGNAL) noexcept
Attempt to write up to
_data.size() - _offset
bytes from the span at the given offset.If _data.size() - _offset is larger then kMaxWrite, then kMaxWrite is used as the max.
- Parameters
_data – The buffer to write from.
_offset – The offset from where to start writing from.
_flags – Any flags to pass to send. MSG_NOSIGNAL is always set additionally. @co_return int The amount of bytes written or -1 if an error occurred.
-
inline auto write(std::span<const DataType> _data, size_t _offset = 0, int _flags = MSG_NOSIGNAL) noexcept
Attempt to write up to
_data.size() - _offset
bytes from the span at the given offset. Blocks until the amount is written or an error occurs.If _data.size() - _offset is larger then kMaxWrite, then kMaxWrite is used as the max.
Coroutine chaining can be expensive exspecially if the call to
write()
is within a hotpath. As such, if the writing is not in a hotpath or are in not performance critical parts of the programwrite()
is encrouaged for readability an maintainabilty. Otherwise authors are encoruged to use write_some and handle their own logic for when the incorrect amount is written.- Parameters
_data – The buffer to write from.
_offset – The offset from where to start writing from.
_flags – Any flags to pass to send. MSG_NOSIGNAL is always set additionaly. @co_return long long The amount of bytes written.
Public Static Attributes
-
static constexpr auto kMaxWrite = std::numeric_limits<std::uint16_t>::max()
The maximum a write_some operation will write to a stream.
-
static constexpr auto kMaxRead = std::numeric_limits<int>::max() - 2
The maximum a read_some operation will write to a stream.
Friends
-
template<MemoryType DT1, MemoryType DT2>
inline friend void swap(tcp_stream<DT1> &_first, tcp_stream<DT2> &_second) noexcept Swaps two tcp streams.
- Template Parameters
DT1 – The memory type of the first one.
DT2 – The memory type of the second one.
- Parameters
_first – The first stream.
_second – The second stream.
-
template<MemoryType DT1>
inline friend void swap(tcp_stream<DT1> &_first, tcp_stream<DT1> &_second) noexcept Swaps two tcp streams.
- Template Parameters
DT1 – The memory type of the first one.
- Parameters
_first – The first stream.
_second – The second stream.
-
template<MemoryType DT1, MemoryType DT2>
inline friend tcp_stream<DT1> rebind(tcp_stream<DT2> &_other) Rebinds the memory type of the stream via a swap.
- Template Parameters
DT1 – The memory type of the resulting stream.
DT2 – The memory type of the resulting to swap.
- Parameters
_other – The stream to rebind.
- Returns
tcp_stream<DT1> The newly typed stream.