c++ boost boost-asio

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.