]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/ |
2 | / Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) | |
3 | / | |
4 | / Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | /] | |
7 | ||
8 | [section:buffers Buffers] | |
9 | ||
10 | Fundamentally, I/O involves the transfer of data to and from contiguous regions | |
11 | of memory, called buffers. These buffers can be simply expressed as a tuple | |
12 | consisting of a pointer and a size in bytes. However, to allow the development | |
13 | of efficient network applications, Boost.Asio includes support for scatter-gather | |
14 | operations. These operations involve one or more buffers: | |
15 | ||
16 | * A scatter-read receives data into multiple buffers. | |
17 | * A gather-write transmits multiple buffers. | |
18 | ||
19 | Therefore we require an abstraction to represent a collection of buffers. The | |
20 | approach used in Boost.Asio is to define a type (actually two types) to | |
21 | represent a single buffer. These can be stored in a container, which may be | |
22 | passed to the scatter-gather operations. | |
23 | ||
24 | In addition to specifying buffers as a pointer and size in bytes, Boost.Asio makes a | |
25 | distinction between modifiable memory (called mutable) and non-modifiable | |
26 | memory (where the latter is created from the storage for a const-qualified | |
27 | variable). These two types could therefore be defined as follows: | |
28 | ||
29 | typedef std::pair<void*, std::size_t> mutable_buffer; | |
30 | typedef std::pair<const void*, std::size_t> const_buffer; | |
31 | ||
32 | Here, a mutable_buffer would be convertible to a const_buffer, but conversion | |
33 | in the opposite direction is not valid. | |
34 | ||
35 | However, Boost.Asio does not use the above definitions as-is, but instead defines two | |
36 | classes: `mutable_buffer` and `const_buffer`. The goal of these is to provide | |
37 | an opaque representation of contiguous memory, where: | |
38 | ||
39 | * Types behave as std::pair would in conversions. That is, a `mutable_buffer` is | |
40 | convertible to a `const_buffer`, but the opposite conversion is disallowed. | |
41 | ||
42 | * There is protection against buffer overruns. Given a buffer instance, a user | |
43 | can only create another buffer representing the same range of memory or a | |
44 | sub-range of it. To provide further safety, the library also includes | |
45 | mechanisms for automatically determining the size of a buffer from an array, | |
46 | `boost::array` or `std::vector` of POD elements, or from a `std::string`. | |
47 | ||
48 | * Type safety violations must be explicitly requested using the `buffer_cast` | |
49 | function. In general an application should never need to do this, but it is | |
50 | required by the library implementation to pass the raw memory to the | |
51 | underlying operating system functions. | |
52 | ||
53 | Finally, multiple buffers can be passed to scatter-gather operations (such as | |
54 | [link boost_asio.reference.read read()] or [link boost_asio.reference.write write()]) by | |
55 | putting the buffer objects into a container. The `MutableBufferSequence` and | |
56 | `ConstBufferSequence` concepts have been defined so that containers such as | |
57 | `std::vector`, `std::list`, `std::vector` or `boost::array` can be used. | |
58 | ||
59 | [heading Streambuf for Integration with Iostreams] | |
60 | ||
61 | The class `boost::asio::basic_streambuf` is derived from `std::basic_streambuf` to | |
62 | associate the input sequence and output sequence with one or more objects of | |
63 | some character array type, whose elements store arbitrary values. These | |
64 | character array objects are internal to the streambuf object, but direct access | |
65 | to the array elements is provided to permit them to be used with I/O | |
66 | operations, such as the send or receive operations of a socket: | |
67 | ||
68 | * The input sequence of the streambuf is accessible via the [link | |
69 | boost_asio.reference.basic_streambuf.data data()] member function. The return type | |
70 | of this function meets the `ConstBufferSequence` requirements. | |
71 | ||
72 | * The output sequence of the streambuf is accessible via the [link | |
73 | boost_asio.reference.basic_streambuf.data prepare()] member function. The return | |
74 | type of this function meets the `MutableBufferSequence` requirements. | |
75 | ||
76 | * Data is transferred from the front of the output sequence to the back of the | |
77 | input sequence by calling the [link boost_asio.reference.basic_streambuf.commit | |
78 | commit()] member function. | |
79 | ||
80 | * Data is removed from the front of the input sequence by calling the [link | |
81 | boost_asio.reference.basic_streambuf.consume consume()] member function. | |
82 | ||
83 | The streambuf constructor accepts a `size_t` argument specifying the maximum of | |
84 | the sum of the sizes of the input sequence and output sequence. Any operation | |
85 | that would, if successful, grow the internal data beyond this limit will throw | |
86 | a `std::length_error` exception. | |
87 | ||
88 | [heading Bytewise Traversal of Buffer Sequences] | |
89 | ||
90 | The `buffers_iterator<>` class template allows buffer sequences (i.e. types | |
91 | meeting `MutableBufferSequence` or `ConstBufferSequence` requirements) to be | |
92 | traversed as though they were a contiguous sequence of bytes. Helper functions | |
93 | called buffers_begin() and buffers_end() are also provided, where the | |
94 | buffers_iterator<> template parameter is automatically deduced. | |
95 | ||
96 | As an example, to read a single line from a socket and into a `std::string`, | |
97 | you may write: | |
98 | ||
99 | boost::asio::streambuf sb; | |
100 | ... | |
101 | std::size_t n = boost::asio::read_until(sock, sb, '\n'); | |
102 | boost::asio::streambuf::const_buffers_type bufs = sb.data(); | |
103 | std::string line( | |
104 | boost::asio::buffers_begin(bufs), | |
105 | boost::asio::buffers_begin(bufs) + n); | |
106 | ||
107 | [heading Buffer Debugging] | |
108 | ||
109 | Some standard library implementations, such as the one that ships with | |
110 | Microsoft Visual C++ 8.0 and later, provide a feature called iterator | |
111 | debugging. What this means is that the validity of iterators is checked at | |
112 | runtime. If a program tries to use an iterator that has been invalidated, an | |
113 | assertion will be triggered. For example: | |
114 | ||
115 | std::vector<int> v(1) | |
116 | std::vector<int>::iterator i = v.begin(); | |
117 | v.clear(); // invalidates iterators | |
118 | *i = 0; // assertion! | |
119 | ||
120 | Boost.Asio takes advantage of this feature to add buffer debugging. Consider the | |
121 | following code: | |
122 | ||
123 | void dont_do_this() | |
124 | { | |
125 | std::string msg = "Hello, world!"; | |
126 | boost::asio::async_write(sock, boost::asio::buffer(msg), my_handler); | |
127 | } | |
128 | ||
129 | When you call an asynchronous read or write you need to ensure that the buffers | |
130 | for the operation are valid until the completion handler is called. In the | |
131 | above example, the buffer is the `std::string` variable `msg`. This variable is | |
132 | on the stack, and so it goes out of scope before the asynchronous operation | |
133 | completes. If you're lucky then the application will crash, but random failures | |
134 | are more likely. | |
135 | ||
136 | When buffer debugging is enabled, Boost.Asio stores an iterator into the string until | |
137 | the asynchronous operation completes, and then dereferences it to check its | |
138 | validity. In the above example you would observe an assertion failure just | |
139 | before Boost.Asio tries to call the completion handler. | |
140 | ||
141 | This feature is automatically made available for Microsoft Visual Studio 8.0 or | |
142 | later and for GCC when `_GLIBCXX_DEBUG` is defined. There is a performance cost | |
143 | to this checking, so buffer debugging is only enabled in debug builds. For | |
144 | other compilers it may be enabled by defining `BOOST_ASIO_ENABLE_BUFFER_DEBUGGING`. | |
145 | It can also be explicitly disabled by defining `BOOST_ASIO_DISABLE_BUFFER_DEBUGGING`. | |
146 | ||
147 | [heading See Also] | |
148 | ||
149 | [link boost_asio.reference.buffer buffer], | |
150 | [link boost_asio.reference.buffers_begin buffers_begin], | |
151 | [link boost_asio.reference.buffers_end buffers_end], | |
152 | [link boost_asio.reference.buffers_iterator buffers_iterator], | |
153 | [link boost_asio.reference.const_buffer const_buffer], | |
154 | [link boost_asio.reference.const_buffers_1 const_buffers_1], | |
155 | [link boost_asio.reference.mutable_buffer mutable_buffer], | |
156 | [link boost_asio.reference.mutable_buffers_1 mutable_buffers_1], | |
157 | [link boost_asio.reference.streambuf streambuf], | |
158 | [link boost_asio.reference.ConstBufferSequence ConstBufferSequence], | |
159 | [link boost_asio.reference.MutableBufferSequence MutableBufferSequence], | |
160 | [link boost_asio.examples.cpp03_examples.buffers buffers example (C++03)], | |
161 | [link boost_asio.examples.cpp11_examples.buffers buffers example (c++11)]. | |
162 | ||
163 | [endsect] |