boost::asio
or its subspace, consider them:boost::asio
: This is where all the main classes and functions are located. The main classes are io_service
and streambuf
. Here are functions such as read, read_at, read_until
, their asynchronous copies, as well as write functions and their asynchronous copies.boost::asio::ip
: This is where the network part of the library is located. The main classes are address, endpoint, tcp, udp, icmp
, and the main functions are connect
and async_connect
. Note that socket
in boost::asio::ip::tcp::socket
is just a typedef
inside the class boost::asio::ip::tcp
.boost::asio::error
: This namespace contains error codes that you can get when you call an I / O subroutine.boost::asio::ssl
: This namespace contains classes that deal with SSL.boost::asio::local
: This namespace contains POSIX-specific classes.boost::asio::windows
: This namespace contains Windows-specific classes.ip::address, ip::address_v4
and ip::address_v6
.ip::address(v4_or_v6_address)
: This function converts a v4 or v6 address to ip::address
ip::address:from_string(str)
: This function creates an address from an IPv4 address (separated by dots) or from IPv6 (hexadecimal format)ip::address::to_string()
: This function returns the address representation in a favorable string format.ip::address_v4::broadcast([addr, mask])
: This function creates a broadcast
address.ip::address_v4::any()
: This function returns an address that impersonates any address.ip::address_v4::loopback(), ip_address_v6::loopback()
: This function returns a loop of addresses (from the v4 / v6 protocol)ip::host_name()
: This function returns the name of the current host as a string.ip::address::from_string
: ip::address addr = ip::address::from_string("127.0.0.1");
// throws an exception ip::address addr = ip::address::from_string("www.yahoo.com");
ip::tcp::endpoint, ip::udp::endpoint
, and ip::icmp::endpoint
.localhost
on port 80, then you need to write the following: ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 80);
endpoint()
: the default constructor and it can sometimes be used for UDP / ICMP socketsendpoint(protocol, port)
: typically used on server sockets to accept new connectionsendpoint(addr, port)
: create endpoint by address and port ip::tcp::endpoint ep1; ip::tcp::endpoint ep2(ip::tcp::v4(), 80); ip::tcp::endpoint ep3( ip::address::from_string("127.0.0.1), 80);
// outputs "87.248.122.122" io_service service; ip::tcp::resolver resolver(service); ip::tcp::resolver::query query("www.yahoo.com", "80"); ip::tcp::resolver::iterator iter = resolver.resolve( query); ip::tcp::endpoint ep = *iter; std::cout << ep.address().to_string() << std::endl;
resolve()
. If successful, at least one entry will be returned. std::cout << ep.address().to_string() << ":" << ep.port() << "/" << ep.protocol() << std::endl;
ip::tcp, ip::udp
, and ip::icmp
, and, of course, it expands. You can create your own socket class, although it is rather difficult. In case you still decide to do this, look at boost/ asio/ip/tcp.hpp
, boost/asio/ip/udp.hpp
, and boost/asio/ip/icmp.hpp
. All of them are pretty small classes with internal typedef
keywords.ip::tcp, ip::udp, ip::icmp
as placeholders; they allow easy access to other classes / functions, which are defined as follows:socket
class creates the corresponding socket. You always pass an instance of io_service
to the constructor: io_service service; ip::udp::socket sock(service) sock.set_option(ip::udp::socket::reuse_address(true));
typedef
:ip::tcp::socket= basic_stream_socket
ip::udp::socket= basic_datagram_socket<ud
p>ip::icmp::socket= basic_raw_socket
sync_func( arg1, arg2 ... argN); // throws boost::system::error_code ec; sync_func( arg1 arg2, ..., argN, ec); // returns error code
assign(protocol,socket)
: this function assigns a raw (natural) socket to a socket instance. Use it when working with legacy code (that is, when raw sockets have already been created).open(protocol)
: this function opens a socket with the specified IP protocol (v4 or v6). You will use it mainly for UDP / ICMP sockets or server sockets.bind(endpoint)
: this function is associated with the given address.connect(endpoint)
: this function is synchronously connected to this address.async_connect(endpoint)
: this function is connected asynchronously to this address.is_open()
: this function returns true if the socket is open.close()
: this function closes the socket. Any asynchronous operation on this socket is immediately terminated and the error::operation_aborted
error code is returned.shutdown(type_of_shutdown)
: this function disables the send , receive
or both operation immediately after the call.cancel()
: this function cancels all asynchronous operations on this socket. All asynchronous operations on this socket will be completed immediately and error::operation_aborted
code will be returned to error::operation_aborted
. ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 80); ip::tcp::socket sock(service); sock.open(ip::tcp::v4()); sock.connect(ep); sock.write_some(buffer("GET /index.html\r\n")); char buff[1024]; sock.read_some(buffer(buff,1024)); sock.shutdown(ip::tcp::socket::shutdown_receive); sock.close();
void handler(const boost::system::error_code& e, size_t bytes);
. But the functions themselves:async_receive(buffer, [flags,] handler)
: this function starts an asynchronous operation to receive data from a socket.async_read_some(buffer,handler)
: this function is equivalent to async_receive(buffer, handler)
.async_receive_from(buffer, endpoint[, flags], handler)
: this function starts asynchronous data reception from a specific address.async_send(buffer [, flags], handler)
: this function starts an asynchronous transfer of data from the bufferasync_write_some(buffer, handler)
: this function is equivalent to async_send(buffer, handler)
.async_send_to(buffer, endpoint, handler)
: this function starts an asynchronous transfer of data from the buffer to a specific address.receive(buffer [, flags])
: this function receives data in the buffer synchronously. The function is blocked until data starts to arrive or if an error has occurred.read_some(buffer)
: this function is equivalent to receive(buffer)
.receive_from(buffer, endpoint [, flags])
: this function synchronously receives data from a specific address into this buffer. The function is blocked until data has started to arrive, or if an error has occurred.send(buffer [, flags])
: this function synchronously sends data from the buffer. The function is locked while data is being sent or if an error has occurred.write_some(buffer)
: this function is equivalent to send(buffer)
.send_to(buffer, endpoint [, flags])
: this function synchronously transfers data from the buffer to this address. The function is locked while data is being sent or if an error has occurred.available()
: this function returns the number of bytes that can be read synchronously, without blocking.ip::socket_type::socket::message_peek
: this flag only looks in the message. He will return the message, but on the next call, you will need to re-read it to read the message.ip::socket_type::socket::message_out_of_band
: this flag processes out-of-band data. OOB data is data that is flagged as more important than normal data. Discussing OOB data is beyond the scope of this book.ip::socket_type::socket::message_do_not_route
: This flag indicates that a message should be sent without using routing tables.ip::socket_type::socket::message_end_of_record:
This flag indicates that the data is marked with a marker about the end of the record. This is not supported on Windows.message_peek
if you ever wrote the following code: char buff[1024]; sock.receive(buffer(buff), ip::tcp::socket::message_peek ); memset(buff,1024, 0); // re-reads what was previously read sock.receive(buffer(buff) );
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 80); ip::tcp::socket sock(service); sock.connect(ep); sock.write_some(buffer("GET /index.html\r\n")); std::cout << "bytes available " << sock.available() << std::endl; char buff[512]; size_t read = sock.read_some(buffer(buff));
ip::udp::socket sock(service); sock.open(ip::udp::v4()); ip::udp::endpoint receiver_ep("87.248.112.181", 80); sock.send_to(buffer("testing\n"), receiver_ep); char buff[512]; ip::udp::endpoint sender_ep; sock.receive_from(buffer(buff), sender_ep);
receive_from
, you need to use the default endpoint constructor, as shown in the previous example. using namespace boost::asio; io_service service; ip::udp::socket sock(service); boost::asio::ip::udp::endpoint sender_ep; char buff[512]; void on_read(const boost::system::error_code & err, std::size_t read_bytes) { std::cout << "read " << read_bytes << std::endl; sock.async_receive_from(buffer(buff), sender_ep, on_read); } int main(int argc, char* argv[]) { ip::udp::endpoint ep( ip::address::from_string("127.0.0.1"), 8001); sock.open(ep.protocol()); sock.set_option(boost::asio::ip::udp::socket::reuse_ address(true)); sock.bind(ep); sock.async_receive_from(buffer(buff,512), sender_ep, on_read); service.run(); }
get_io_service()
: this function returns an instance of io_service
, which was passed to the constructor.get_option(option)
: this function returns a socket parameterset_option(option)
: this function sets the socket parameterio_control(cmd)
: this function executes I / O commands on the socket.Name | Definition | Type of |
---|---|---|
broadcast | If true , then allows broadcast messages | bool |
debug | If true , it allows debugging at the socket level. | bool |
do_not_route | If true , it prevents routing and uses only local interfaces. | bool |
enable_connection_aborted | If true , then reconnects the broken connection. | bool |
keep_alive | If true , send keep-alives | bool |
linger | If true , the socket is delayed by close() , if there are no saved onesdata | bool |
receive_buffer_size | Receive Buffer Size | int |
receive_low_watemark | Provides the minimum number of bytes when processing an input socket. | int |
reuse_address | If true , the socket may be associated with an address that is already in use. | bool |
send_buffer_size | Send buffer size | int |
send_low_watermark | Provides the minimum number of bytes to send in the output socket. | int |
ip::v6_only | If true , it allows using only IPv6 communications. | bool |
typedef
socket or class. Here's how to use them: ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 80); ip::tcp::socket sock(service); sock.connect(ep); // TCP socket can reuse address ip::tcp::socket::reuse_address ra(true); sock.set_option(ra); // get sock receive buffer size ip::tcp::socket::receive_buffer_size rbs; sock.get_option(rbs); std::cout << rbs.value() << std::endl; // set sock's buffer size to 8192 ip::tcp::socket::send_buffer_size sbs(8192); sock.set_option(sbs);
Name | Tcp | UDP | ICMP |
---|---|---|---|
async_read_some | Yes | - | - |
async_write_some | Yes | - | - |
async_send_to | - | Yes | Yes |
read_some | Yes | - | - |
receive_from | - | Yes | Yes |
write_some | Yes | - | - |
send_to | - | Yes | Yes |
local_endpoint()
: This function returns an address if the socket is connected locally.remote_endpoint()
: this function returns the remote addresses to which the socket was connected.native_handle()
: this function returns a clean socket. It should be used only when you want to use functions for working with clean sockets that are not supported by Boost.Asio.non_blocking()
: this function returns true
if the socket is non-blocking, otherwise false
.native_non_blocking()
: this function returns true
if the socket is non-blocking, otherwise false
. However, it will call a clean API for the natural socket. As a rule, you do not need this ( non_blocking()
always caches this result); you should use it only when you are directly dealing with native_handle()
.at_mark()
: this function returns true
if you intend to read OOB data in the socket. She is needed very rarely.operator=
not available. ip::tcp::socket s1(service), s2(service); s1 = s2; // compile time error ip::tcp::socket s3(s1); // compile time error
shared
pointer). typedef boost::shared_ptr<ip::tcp::socket> socket_ptr; socket_ptr sock1(new ip::tcp::socket(service)); socket_ptr sock2(sock1); // ok socket_ptr sock3; sock3 = sock1; // ok
buff
course, buff
must survive both receive
and send
operations: char buff[512]; ... sock.receive(buffer(buff)); strcpy(buff, "ok\n"); sock.send(buffer(buff));
// very bad code ... void on_read(const boost::system::error_code & err, std::size_t read_ bytes) { ... } void func() { char buff[512]; sock.async_receive(buffer(buff), on_read); }
async_receive()
, the buff
will go out of scope, thus its memory will be freed. When we are going to actually get some data on the socket, we need to copy it into memory no longer belong to us; it can be either released or redistributed by code for other data, while all have memory corruption. void on_read(char * ptr, const boost::system::error_code & err, std::size_t read_bytes) { delete[] ptr; } .... char * buff = new char[512]; sock.async_receive(buffer(buff, 512), boost::bind(on_ read,buff,_1,_2));
shared pointer
: struct shared_buffer { boost::shared_array<char> buff; int size; shared_buffer(size_t size) : buff(new char[size]), size(size) {} mutable_buffers_1 asio_buff() const { return buffer(buff.get(), size); } }; // when on_read goes out of scope, the boost::bind object is released, // and that will release the shared_buffer as well void on_read(shared_buffer, const boost::system::error_code & err, std::size_t read_bytes) {} ... shared_buffer buff(512); sock.async_receive(buff.asio_buff(), boost::bind(on_read,buff,_1,_2));
shared_buffer
contains inside itself shared_array<>
, which is a copy of the shared_buffer
instance, so shared_array <>
will remain alive; when the latter goes out of scope, shared_array <>
automatically collapses, just what we wanted.boost::bind
functor that internally stores a copy of our shared_buffer
instance. It is very neat!buffer()
call and its function transfer: char buff[512]; sock.async_receive(buffer(buff), on_read
sock.async_receive(some_buffer, on_read);
some_buffer
must satisfy some requirements, namely ConstBufferSequence
or MutableBufferSequence
(you can see more about them in the Boost.Asio documentation). The details of creating your own class to meet these requirements are quite complex, but Boost.Asio already contains some classes that model these requirements. You do not access them directly, you use the buffer()
function.buffer()
function:void*
and size in charactersstd::string
std::vector
from any PODboost::array
from any PODstd::array
from any POD struct pod_sample { int i; long l; char c; }; ... char b1[512]; void * b2 = new char[512]; std::string b3; b3.resize(128); pod_sample b4[16]; std::vector<pod_sample> b5; b5.resize(16); boost::array<pod_sample,16> b6; std::array<pod_sample,16> b7; sock.async_send(buffer(b1), on_read); sock.async_send(buffer(b2,512), on_read); sock.async_send(buffer(b3), on_read); sock.async_send(buffer(b4), on_read); sock.async_send(buffer(b5), on_read); sock.async_send(buffer(b6), on_read); sock.async_send(buffer(b7), on_read);
ConstBufferSequence
MutableBufferSequence
, , , mutable_ buffers_1
, , shared_buffer
.connect(socket, begin [, end] [, condition])
: , begin
end
. begin
socket_type::resolver::query
( , « » ). , . condition
, . Iterator connect_condition(const boost::system::error_code & err, Iterator next);
. , , .async_connect(socket, begin [, end] [, condition], handler):
. void handler(const boost::system::error_code & err, Iterator iterator);
. , ( end ). using namespace boost::asio::ip; tcp::resolver resolver(service); tcp::resolver::iterator iter = resolver.resolve(tcp::resolver::query("www.yahoo.com","80")); tcp::socket sock(service); connect(sock, iter);
connect
async_connect
, ; .async_read(stream, buffer [, completion] ,handler)
: . . void handler(const boost::system::error_code & err, size_t bytes);
. completion . Completion
read
, Boost.Asio async_read
( , ). size_t completion (const boost::system::error_code& err, size_t bytes_transfered)
. 0, , ; , , async_read_some
. .async_write(stream, buffer [, completion], handler)
: . async_read
.read(stream, buffer [, completion])
: . async_read
write(stream, buffer [, completion])
: . async_read
.async_read(stream, stream_buffer [, completion], handler)
async_write(strean, stream_buffer [, completion], handler)
write(stream, stream_buffer [, completion])
read(stream, stream_buffer [, completion])
Completion
0 ( ). io_service service; ip::tcp::socket sock(service); char buff[512]; int offset = 0; size_t up_to_enter(const boost::system::error_code &, size_t bytes) { for ( size_t i = 0; i < bytes; ++i) if ( buff[i + offset] == '\n') return 0; return 1; } void on_read(const boost::system::error_code &, size_t) {} ... async_read(sock, buffer(buff), up_to_enter, on_read);
completion
: char buff[512]; void on_read(const boost::system::error_code &, size_t) {} // read exactly 32 bytes async_read(sock, buffer(buff), transfer_exactly(32), on_read);
stream_buffer
Boost.Asio, std::streambuf
. STL , : io_service service; void on_read(streambuf& buf, const boost::system::error_code &, size_t) { std::istream in(&buf); std::string line; std::getline(in, line); std::cout << "first line: " << line << std::endl; } int main(int argc, char* argv[]) { HANDLE file = ::CreateFile("readme.txt", GENERIC_READ, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,0); windows::stream_handle h(service, file); streambuf buf; async_read(h, buf, transfer_exactly(256), boost::bind(on_read,boost::ref(buf),_1,_2)); service.run(); }
async_read
( - ) Windows. 256 . , on_read
, std::istream
, ( std::getline
) .read_until/async_read_until
async_read_until(stream, stream_buffer, delim, handler)
: . ( delim
). , std::string
boost::regex
. void handler(const boost::system::error_code & err, size_t bytes);
.async_read_until(stream, stream_buffer, completion, handler)
: , . pair<iterator,bool> completion(iterator begin, iterator end);
, buffers_iterator<streambuf::const_buffers_type>
. , . ( begin, end
) . ; ; true
, , , false
.read_until(stream, stream_buffer, delim)
: . async_read_until
. typedef buffers_iterator<streambuf::const_buffers_type> iterator; std::pair<iterator, bool> match_punct(iterator begin, iterator end) { while ( begin != end) if ( std::ispunct(*begin)) return std::make_pair(begin,true); return std::make_pair(end,false); } void on_read(const boost::system::error_code &, size_t) {} ... streambuf buf; async_read_until(sock, buf, match_punct, on_read);
async_read_until(sock, buff, ' ', on_read);
async_read_at(stream, offset, buffer [, completion], handler)
: , offset
. handler (const boost::system::error_code& err, size_t bytes);
. buffer()
streambuf
. , Boost.Asio async_read_at operation
( , ). size_t completion(const boost::system::error_code& err, size_t bytes);
. 0, , , , , async_read_some_at
.async_write_at(stream, offset, buffer [, completion], handler)
: . async_read_at
.read_at(stream, offset, buffer [, completion])
: . async_read_at
.read_at(stream, offset, buffer [, completion])
: . async_read_at
.forward-only
). io_service service; int main(int argc, char* argv[]) { HANDLE file = ::CreateFile("readme.txt", GENERIC_READ, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,0); windows::random_access_handle h(service, file); streambuf buf; read_at(h, 256, buf, transfer_exactly(128)); std::istream in(&buf); std::string line; std::getline(in, line); std::cout << "first line: " << line << std::endl; }
Source: https://habr.com/ru/post/193038/
All Articles