Boost::Asio::Basic
To perform I/O operations your program will need an I/O object such as a TCP socket:
boost::asio::ip::tcp::socket socket(io_service);
When a synchronous connect operation is performed, the following sequence of events occurs:
1. Your program initiates the connect operation
by calling the I/O object:
socket.connect(server_endpoint);
2. The I/O object forwards the request to the io_service.
3. The io_service calls on the operating system to perform the connect operation.
4. The operating system returns the result of the operation to the io_service.
5. The io_service translates any error resulting from the operation into a boost::system::error_code. An error_code may be compared with specific values, or tested as a boolean (where a false result means that no error occurred). The result is then forwarded back up to the I/O object.
6. The I/O object throws an exception of type boost::system::system_error if the operation failed. If the code to initiate the operation had instead been written as:
boost::system::error_code ec;
socket.connect(server_endpoint, ec);
then the error_code variable ec would be set to the result of the operation, and no exception would be thrown.
When an asynchronous operation is used, a different sequence of events occurs.
1. Your program initiates the connect operation by calling the I/O object:
socket.async_connect(server_endpoint, your_completion_handler);
where your_completion_handler is a function or function object with the signature:
void your_completion_handler(const boost::system::error_code& ec);
The exact signature required depends on the asynchronous operation being performed. The reference documentation indicates the appropriate form for each operation.
2. The I/O object forwards the request to the io_service.
3. The io_service signals to the operating system that it should start an asynchronous connect.
Time passes. (In the synchronous case this wait would have been contained entirely within the duration of the connect operation.)
4. The operating system indicates that the connect operation has completed by placing the result on a queue, ready to be picked up by the io_service.
5. Your program must make a call to io_service::run() (or to one of the similar io_service member functions) in order for the result to be retrieved. A call to io_service::run()
blocks while there are unfinished asynchronous operations, so you would
typically call it as soon as you have started your first asynchronous
operation.
6. While inside the call to io_service::run(), the io_service dequeues the result of the operation, translates it into an error_code, and then passes it to your completion handler.
Remark:不管在同步还是在异步的网络连接上,都是我们的I/O object(这是具体需要的连接类型)来进行操作。而在I/O Object则是和I/O Service进行交互来获得或者发出信息。最后,I/O 与System进行底层的交互。故而根据估计:
I/O Service 是对系统的抽象而达到真正的Cross-Platform
I/O Object 是对于具体服务的更上一层的抽象.
Buffers
Fundamentally, I/O involves the transfer of data to and from contiguous regions of memory, called buffers. These buffers can be simply expressed as a tuple consisting of a pointer and a size in bytes. However, to allow the development of efficient network applications, Boost.Asio includes support for scatter-gather operations. These operations involve one or more buffers:
- A scatter-read receives data into multiple buffers.
- A gather-write transmits multiple buffers.
Therefore we require an abstraction to represent a collection of buffers. The approach used in Boost.Asio is to define a type (actually two types) to represent a single buffer. These can be stored in a container, which may be passed to the scatter-gather operations.
In addition to specifying buffers as a pointer and size in bytes, Boost.Asio makes a distinction between modifiable memory (called mutable) and non-modifiable memory (where the latter is created from the storage for a const-qualified variable). These two types could therefore be defined as follows:
typedef std::pair<void*, std::size_t> mutable_buffer;
typedef std::pair<const void*, std::size_t> const_buffer;
Here, a mutable_buffer would be convertible to a const_buffer, but conversion in the opposite direction is not valid.
However, Boost.Asio does not use the above definitions as-is, but instead
defines two classes: mutable_buffer
and const_buffer. The goal
of these is to provide an opaque representation of contiguous memory, where:
-
Types behave as std::pair would in conversions. That is, a
mutable_bufferis convertible to aconst_buffer, but the opposite conversion is disallowed. -
There is protection against buffer overruns. Given a buffer instance,
a user can only create another buffer representing the same range of
memory or a sub-range of it. To provide further safety, the library also
includes mechanisms for automatically determining the size of a buffer
from an array,
boost::arrayorstd::vectorof POD elements, or from astd::string. -
Type safety violations must be explicitly requested using the
buffer_castfunction. In general an application should never need to do this, but it is required by the library implementation to pass the raw memory to the underlying operating system functions.
Finally, multiple buffers can be passed to scatter-gather operations (such
as read() or write())
by putting the buffer objects into a container. The MutableBufferSequence
and ConstBufferSequence
concepts have been defined so that containers such as std::vector,
std::list, std::vector
or boost::array can be used.
Streambuf for Integration with Iostreams
The class boost::asio::basic_streambuf is derived from std::basic_streambuf to associate the input
sequence and output sequence with one or more objects of some character
array type, whose elements store arbitrary values. These character array
objects are internal to the streambuf object, but direct access to the
array elements is provided to permit them to be used with I/O operations,
such as the send or receive operations of a socket:
-
The input sequence of the streambuf is accessible via the data()
member function. The return type of this function meets the
ConstBufferSequencerequirements. -
The output sequence of the streambuf is accessible via the prepare()
member function. The return type of this function meets the
MutableBufferSequencerequirements. - Data is transferred from the front of the output sequence to the back of the input sequence by calling the commit() member function.
- Data is removed from the front of the input sequence by calling the consume() member function.
The streambuf constructor accepts a size_t
argument specifying the maximum of the sum of the sizes of the input sequence
and output sequence. Any operation that would, if successful, grow the
internal data beyond this limit will throw a std::length_error
exception.
Bytewise Traversal of Buffer Sequences
The buffers_iterator<>
class template allows buffer sequences (i.e. types meeting MutableBufferSequence or ConstBufferSequence requirements) to
be traversed as though they were a contiguous sequence of bytes. Helper
functions called buffers_begin() and buffers_end() are also provided, where
the buffers_iterator<> template parameter is automatically deduced.
As an example, to read a single line from a socket and into a std::string, you may write:
boost::asio::streambuf sb;
...
std::size_t n = boost::asio::read_until(sock, sb, '\n');
boost::asio::streambuf::const_buffers_type bufs = sb.data();
std::string line(
boost::asio::buffers_begin(bufs),
boost::asio::buffers_begin(bufs) + n);
Remark: Buffer就是一个充当缓存的内存区域,可以通过Byte或者类型的格式进行读入或者读出。显然就是一串比特,填充或者将缓存清空等等的事情都是系统来作的。
Many I/O objects in Boost.Asio are stream-oriented. This means that:
There are no message boundaries. The data being transferred is a continuous sequence of bytes. Read or write operations may transfer fewer bytes than requested. This is referred to as a short read or short write.
Objects that provide stream-oriented I/O model one or more of the following
type requirements:
SyncReadStream, where synchronous read operations are performed using a member function called read_some(). AsyncReadStream, where asynchronous read operations are performed using a member function called async_read_some(). SyncWriteStream, where synchronous write operations are performed using a member function called write_some(). AsyncWriteStream, where synchronous write operations are performed using a member function called async_write_some().
Examples of stream-oriented I/O objects include ip::tcp::socket,
ssl::stream<>,
posix::stream_descriptor, windows::stream_handle,
etc.
Programs typically want to transfer an exact number of bytes. When a short
read or short write occurs the program must restart the operation, and
continue to do so until the required number of bytes has been transferred.
Boost.Asio provides generic functions that do this automatically: read(), async_read(),write() and async_write().
Why EOF is an Error The end of a stream can cause read, async_read, read_until or async_read_until functions to violate their contract. E.g. a read of N bytes may finish early due to EOF. An EOF error may be used to distinguish the end of a stream from a successful read of size
Remark:也就是说如果读取或者写入超出了buffer的size会出现的问题。抛出EOF错误
这些东西看起来云里雾里……唉直接跳到应用方面去,等到遇到问题再跳回来。。。查资料。。。
浙公网安备 33010602011771号