Ch26.4: transmit
1. What transmit Is For
transmit moves bytes from an input device to an output device. It does not
format, parse, or interpret the bytes. It is the third member of the core I/O trio:
print writes values, scan reads values, and
transmit moves a byte stream.
The operation exists because a hand-written loop is easy to get subtly wrong. A single
read may return less than you asked for. A single write may
accept less than it was given. Either may be interrupted. A buffered input device may
already hold bytes that a raw descriptor copy would overtake. transmit
handles all of that in one place.
2. The Two Operations
| Operation | Return | Meaning |
|---|---|---|
::fast_io::operations::transmit_some_bytes(out, off_out, in, off_in, size) |
::std::size_t |
Move at most size bytes. Returns the number actually moved in this
round; 0 means end of input. |
::fast_io::operations::transmit_all_bytes(out, off_out, in, off_in, total) |
void |
Repeat until end of input or until the optional bound is exhausted. |
off_out and off_in are fpos_nullable_ptr values.
Pass {} to use and advance the device's own position. Pass an
intfpos_t by reference to transfer at an explicit offset without moving the
device's own position; the referenced value is advanced past the transferred bytes.
total is a size_t_opt. {} means “until EOF”;
::fast_io::size_t_opt{n} means “at most n bytes”. This is the
bound for protocols that already know the body length.
3. File-to-File
#include <fast_io.h>
int main()
{
::fast_io::ibuf_file in("input.bin");
::fast_io::obuf_file out("output.bin");
::fast_io::operations::transmit_all_bytes(out, {}, in, {}, {});
}
No temporary buffer appears in the application code. If the platform and the device
types support a kernel copy path, transmit_all_bytes can use
copy_file_range, splice or sendfile; otherwise it
falls back to a bounded internal buffer. The application does not need two versions of
the copy.
The devices do not have to be files. The same call moves bytes from a pipe to a file, a socket to a file, or a file to a socket. That is why the process and pipe chapter uses the same operation: the child process writes into a pipe, and the parent transmits the pipe into its own output.
4. Bounded Transfer
A protocol that carries a length prefix should pass that length. The transfer stops at the bound even if the input has more bytes:
::std::size_t const body_length{content_length};
::fast_io::operations::transmit_all_bytes(
out, {}, in, {}, ::fast_io::size_t_opt{body_length});
Use transmit_some_bytes when you need the count of bytes moved in this round,
for example to update a progress counter or to interleave several streams. A return value
of 0 means EOF, not an error.
5. Buffered Input and Output
transmit works with buffered and unbuffered devices on both sides. The
implementation is careful about two ordering hazards:
- Input lookahead. A buffered input device may already hold bytes in its buffer. A raw descriptor-to-descriptor copy would skip them. The operation forwards the pending input buffer first, then transfers from the device.
- Output buffer. A buffered output device may hold pending bytes. The operation flushes that buffer before a kernel-level copy, so the destination order is preserved.
This is why transmit is safe on the buffered types used by scan
and print, not only on raw native files.
6. Failure and Partial Progress
Both operations report device failures as herbceptions. A partial transfer is not a
failure: transmit_all_bytes continues until EOF or the bound, and
transmit_some_bytes reports the bytes moved. A byte is counted only after it
has actually reached the output, so a short write does not silently lose input data.
Offsets are a separate failure surface. Passing a non-null output offset to a device
that cannot seek (a pipe or a socket) is an error; pass {} for those devices.
7. transmit vs print vs scan
| Operation | Input | Output | Data |
|---|---|---|---|
print |
values | device | formatted text |
scan |
buffered device | values | parsed text |
transmit |
device | device | raw bytes |
Do not use print to move a binary blob and do not use
transmit to write a number. The boundary is the same one stated in
Ch11.5: bytes use transmit, structured data uses
scan and print.
fast_io module export list does not include
transmit_some_bytes or transmit_all_bytes; use
#include <fast_io.h> until they are exported.
Key Takeaways
transmit_some_bytesmoves one bounded round and returns the byte count;transmit_all_bytesloops to EOF or a bound.- Offsets are optional; pass
{}for pipes, sockets and ordinary streaming. - A return value of
0means EOF, not an error. - The operation forwards buffered input and flushes buffered output before a kernel copy.
- It can use kernel copy paths where available and falls back to a bounded buffer.
- Use transmit for bytes, print for values, scan for parsed input.
- The transmit operations are currently header-side, not in the module export list.