c++ - Boost ASIO streambuf
boost-asio (2)
"Todo es relativo"
Albert Einstein
La boost::asio::streambuf dice:
Los caracteres escritos en la secuencia de salida de un objeto basic_streambuf se agregan a la secuencia de entrada del mismo objeto.
Desde el punto de vista del
streambuf
, leerá su secuencia de salida y escribirá en su secuencia de entrada, lo que puede parecer un poco invertido, pero puede pensar en el
streambuf
como una
pipe
para que las cosas tengan sentido.
Desde el punto de vista del usuario (cualquier cosa que use el
streambuf
, incluidos los sockets) ahora, escribirá en la secuencia de
streambuf
del
streambuf
y leerá desde su secuencia de entrada, lo que parece más natural.
Así que sí, de la misma manera que se invierten izquierda y derecha dependiendo de lo que esté enfrentando, las entradas y salidas se invierten dependiendo de qué lado lo mire.
"No creas cada cita que lees en Internet, porque yo no dije eso"
Albert Einstein
Estoy confundido acerca de la secuencia de entrada y la secuencia de salida en las clases boost asio :: streambuf.
De acuerdo con los ejemplos de código (para enviar datos) en la documentación, parece que el búfer que representa la secuencia de entrada se usa para escribir en el socket y el que representa la secuencia de salida se usa para leer.
Ejemplo
boost::asio::streambuf b;
std::ostream os(&b);
os << "Hello, World!/n";
// try sending some data in input sequence
size_t n = sock.send(b.data());
b.consume(n); // sent data is removed from input sequence
Ahora, ¿hay un problema de nomenclatura?
La nomenclatura para
boost::asio::streambuf
es similar a la que se define en el estándar C ++ y se usa en varias clases en la biblioteca de plantillas estándar, en la que los datos se escriben en una secuencia de salida y los datos se leen desde una secuencia de entrada .
Por ejemplo, uno podría usar
std::cout.put()
para escribir en la secuencia de salida y
std::cin.get()
para leer en la secuencia de entrada.
Al controlar manualmente las
streambuf
entrada y salida de
streambuf
, el ciclo de vida general de los datos es el siguiente:
-
Los buffers se asignan con
prepare()
para la secuencia de salida. -
Después de que los datos se hayan escrito en los búferes de la secuencia de salida, los datos se
commit()
ed. Estos datos comprometidos se eliminan de la secuencia de salida y se agregan a la secuencia de entrada desde la que se pueden leer. -
Los datos se leen de los buffers de la secuencia de entrada obtenidos a través de
data()
. -
Una vez que se han leído los datos, pueden eliminarse de la secuencia de entrada mediante
consume()
.
Cuando se utilizan operaciones Boost.Asio que operan en
streambuf
o objetos de flujo que usan
streambuf
, como
std::ostream
, las secuencias de entrada y salida subyacentes se gestionarán correctamente.
Si se proporciona un búfer a una operación, como pasar pasar
prepare()
a una operación de lectura o
data()
a una operación de escritura, entonces uno debe manejar explícitamente el
commit()
y el
consume()
.
Aquí hay una versión anotada del código de ejemplo que escribe directamente desde un
streambuf
a un socket:
// The input and output sequence are empty.
boost::asio::streambuf b;
std::ostream os(&b);
// prepare() and write to the output sequence, then commit the written
// data to the input sequence. The output sequence is empty and
// input sequence contains "Hello, World!/n".
os << "Hello, World!/n";
// Read from the input sequence, writing to the socket. The input and
// output sequences remain unchanged.
size_t n = sock.send(b.data());
// Remove ''n'' bytes from the input sequence. If the send operation sent
// the entire buffer, then the input sequence would be empty.
b.consume(n);
Y aquí está el ejemplo anotado para leer desde un socket directamente en un
streambuf
.
Las anotaciones suponen que la palabra "hola" ha sido recibida, pero aún no leída, en el zócalo:
boost::asio::streambuf b;
// prepare() 512 bytes for the output sequence. The input sequence
// is empty.
auto bufs = b.prepare(512);
// Read from the socket, writing into the output sequence. The
// input sequence is empty and the output sequence contains "hello".
size_t n = sock.receive(bufs);
// Remove ''n'' (5) bytes from output sequence appending them to the
// input sequence. The input sequence contains "hello" and the
// output sequence has 507 bytes.
b.commit(n);
// The input and output sequence remain unchanged.
std::istream is(&b);
std::string s;
// Read from the input sequence and consume the read data. The string
// ''s'' contains "hello". The input sequence is empty, the output
// sequence remains unchanged.
is >> s;
Observe cómo en los ejemplos anteriores, los objetos de steam manejados comprometidos y consumiendo las secuencias de entrada y salida de streambuf.
Sin embargo, cuando se usaron los buffers (es decir,
data()
y
prepare()
), el código necesitaba manejar explícitamente los commits y consumos.