Create a buffer
In io operations, read and write data mostly in a buffer zone. In the asio framework, you can use the asio: buffer function to create a buffer zone to provide data read and write. The buffer function does not apply for memory, but provides an encapsulation of the existing memory.
Char d1 [128];
Size_t bytes_transferred = sock. receive (asio: buffer (d1 ));
Using strings as a buffer is also a common form:
String str = "hello world ";
Size_t bytes_transferred = sock. send (asio: buffer (str ));
In addition to these basic types, you can also use containers in stl, which is very convenient.
Asio: buffer (std: vector <char> (128 ));
Asio: buffer (std: array <char, 128> ());
Restore the buffer as a data object
The preceding operation encapsulates the data object into a buffer. during use, the buffer must be restored to a data object.
Char * p1 = asio: buffer_cast <char *> (buffer );
Obtain the buffer size.
You can use the buffer_size function to obtain the buffer size.
Size_t s1 = asio: buffer_size (buf );
Read/write buffer
Read/write buffer is generally associated with io objects, and read/write operations are provided in io object member functions. Taking the tcp: socket object as an example, it provides read_some and write_some for read and write operations:
Std: array <char, 128> buf;
Sock. read_some (asio: buffer (buf ));
In addition, the asio namespace also provides general read and write Functions to implement more advanced read and write functions.
Size_t bytes_transfered = asio: read (sock, asio: buffer (buf), asio: transfer_all (), err );
Here I use the transfer_all mark to forcibly read the buffer to return the result. There are also two commonly used tags transfer_at_least () and transfer_exactly (), which are very convenient.
Streambuf
Asio: streambuf provides a stream buffer, which can apply for memory. Its advantage is that it can implement buffer operations through stl stream-related functions, making it easier to process.
// Send data through streambuf
Asio: streambuf B;
Std: ostream OS (& B );
OS <"Hello, World! \ N ";
Size_t n = sock. send (B. data (); // try sending some data in input sequence
B. consume (n); // sent data is removed from input sequence
// Read data through streambuf
Asio: streambuf B;
Asio: streambuf: mutable_buffers_type bufs = B. prepare (512); // reserve 512 bytes in output sequence
Size_t n = sock. receive (bufs );
B. commit (n); // encoded ed data is "committed" from output sequence to input sequence
Std: istream is (& B );
Std: string s;
Is> s;
In addition, the asio namespace also provides a read_until function that can be used to read strings that meet the specified conditions. This function is very useful for parsing protocols.
Size_t n = asio: read_until (sock, stream, '\ n ');
Asio: streambuf: const_buffers_type bufs = sb. data ();
Std: string line (asio: buffers_begin (bufs), asio: buffers_begin (bufs) + n );
In addition to strings, This specified condition can also be a regular expression, which is very powerful. This is why the asio library depends on boost. regex. (Although regex has been standardized, you still need to use the boost. regex library. When can I use the std. regex library after asio is standardized)
Custom Memory Allocation
During asynchronous IO operations, dynamic memory is often applied and released after use. In IO-intensive scenarios, frequent requests to release memory have a great impact on performance. To avoid this problem, asio provides a memory pool model asio_handler_allocate and asio_handler_deallocate to reuse the memory.
I will not write the example. You can refer to the boost official document example or this article on the Internet.
Personally, I am not in favor of using allocator in the early stage of the project. After all, this brings a lot of code complexity. But as a performance optimization point, try again later performance optimization to try it out. The memory pool also has many different solutions, and google-perftools is also worth a try.