diff options
author | 2016-10-07 14:13:19 +0200 | |
---|---|---|
committer | 2016-10-07 14:13:19 +0200 | |
commit | ff01b716711b97c2fcaa709ea97f7650f106aa10 (patch) | |
tree | 50dd4d687f38f50c4e136af030c02c267c769f3a /3rdparty/asio/src/examples/cpp03/tutorial | |
parent | 2a138159c30457aecd9e9679be5159704db0f954 (diff) |
Added ASIO networking library (nw)
Diffstat (limited to '3rdparty/asio/src/examples/cpp03/tutorial')
27 files changed, 1869 insertions, 0 deletions
diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime1/.gitignore b/3rdparty/asio/src/examples/cpp03/tutorial/daytime1/.gitignore new file mode 100644 index 00000000000..2926eaf9bf6 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime1/.gitignore @@ -0,0 +1,10 @@ +client +.deps +.dirstamp +*.o +*.obj +*.exe +*.ilk +*.manifest +*.pdb +*.tds diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime1/client.cpp b/3rdparty/asio/src/examples/cpp03/tutorial/daytime1/client.cpp new file mode 100644 index 00000000000..9784d48a6fb --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime1/client.cpp @@ -0,0 +1,57 @@ +// +// client.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <boost/array.hpp> +#include <asio.hpp> + +using asio::ip::tcp; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: client <host>" << std::endl; + return 1; + } + + asio::io_context io_context; + + tcp::resolver resolver(io_context); + tcp::resolver::results_type endpoints = + resolver.resolve(argv[1], "daytime"); + + tcp::socket socket(io_context); + asio::connect(socket, endpoints); + + for (;;) + { + boost::array<char, 128> buf; + asio::error_code error; + + size_t len = socket.read_some(asio::buffer(buf), error); + + if (error == asio::error::eof) + break; // Connection closed cleanly by peer. + else if (error) + throw asio::system_error(error); // Some other error. + + std::cout.write(buf.data(), len); + } + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime2/.gitignore b/3rdparty/asio/src/examples/cpp03/tutorial/daytime2/.gitignore new file mode 100644 index 00000000000..7f06efb3296 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime2/.gitignore @@ -0,0 +1,10 @@ +server +.deps +.dirstamp +*.o +*.obj +*.exe +*.ilk +*.manifest +*.pdb +*.tds diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime2/server.cpp b/3rdparty/asio/src/examples/cpp03/tutorial/daytime2/server.cpp new file mode 100644 index 00000000000..f662ed246c4 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime2/server.cpp @@ -0,0 +1,50 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <ctime> +#include <iostream> +#include <string> +#include <asio.hpp> + +using asio::ip::tcp; + +std::string make_daytime_string() +{ + using namespace std; // For time_t, time and ctime; + time_t now = time(0); + return ctime(&now); +} + +int main() +{ + try + { + asio::io_context io_context; + + tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 13)); + + for (;;) + { + tcp::socket socket(io_context); + acceptor.accept(socket); + + std::string message = make_daytime_string(); + + asio::error_code ignored_error; + asio::write(socket, asio::buffer(message), ignored_error); + } + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime3/.gitignore b/3rdparty/asio/src/examples/cpp03/tutorial/daytime3/.gitignore new file mode 100644 index 00000000000..7f06efb3296 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime3/.gitignore @@ -0,0 +1,10 @@ +server +.deps +.dirstamp +*.o +*.obj +*.exe +*.ilk +*.manifest +*.pdb +*.tds diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime3/server.cpp b/3rdparty/asio/src/examples/cpp03/tutorial/daytime3/server.cpp new file mode 100644 index 00000000000..cb2c9480594 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime3/server.cpp @@ -0,0 +1,117 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <ctime> +#include <iostream> +#include <string> +#include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <asio.hpp> + +using asio::ip::tcp; + +std::string make_daytime_string() +{ + using namespace std; // For time_t, time and ctime; + time_t now = time(0); + return ctime(&now); +} + +class tcp_connection + : public boost::enable_shared_from_this<tcp_connection> +{ +public: + typedef boost::shared_ptr<tcp_connection> pointer; + + static pointer create(asio::io_context& io_context) + { + return pointer(new tcp_connection(io_context)); + } + + tcp::socket& socket() + { + return socket_; + } + + void start() + { + message_ = make_daytime_string(); + + asio::async_write(socket_, asio::buffer(message_), + boost::bind(&tcp_connection::handle_write, shared_from_this(), + asio::placeholders::error, + asio::placeholders::bytes_transferred)); + } + +private: + tcp_connection(asio::io_context& io_context) + : socket_(io_context) + { + } + + void handle_write(const asio::error_code& /*error*/, + size_t /*bytes_transferred*/) + { + } + + tcp::socket socket_; + std::string message_; +}; + +class tcp_server +{ +public: + tcp_server(asio::io_context& io_context) + : acceptor_(io_context, tcp::endpoint(tcp::v4(), 13)) + { + start_accept(); + } + +private: + void start_accept() + { + tcp_connection::pointer new_connection = + tcp_connection::create(acceptor_.get_executor().context()); + + acceptor_.async_accept(new_connection->socket(), + boost::bind(&tcp_server::handle_accept, this, new_connection, + asio::placeholders::error)); + } + + void handle_accept(tcp_connection::pointer new_connection, + const asio::error_code& error) + { + if (!error) + { + new_connection->start(); + } + + start_accept(); + } + + tcp::acceptor acceptor_; +}; + +int main() +{ + try + { + asio::io_context io_context; + tcp_server server(io_context); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime4/.gitignore b/3rdparty/asio/src/examples/cpp03/tutorial/daytime4/.gitignore new file mode 100644 index 00000000000..2926eaf9bf6 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime4/.gitignore @@ -0,0 +1,10 @@ +client +.deps +.dirstamp +*.o +*.obj +*.exe +*.ilk +*.manifest +*.pdb +*.tds diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime4/client.cpp b/3rdparty/asio/src/examples/cpp03/tutorial/daytime4/client.cpp new file mode 100644 index 00000000000..da3b651d56d --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime4/client.cpp @@ -0,0 +1,52 @@ +// +// client.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <boost/array.hpp> +#include <asio.hpp> + +using asio::ip::udp; + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 2) + { + std::cerr << "Usage: client <host>" << std::endl; + return 1; + } + + asio::io_context io_context; + + udp::resolver resolver(io_context); + udp::endpoint receiver_endpoint = + *resolver.resolve(udp::v4(), argv[1], "daytime").begin(); + + udp::socket socket(io_context); + socket.open(udp::v4()); + + boost::array<char, 1> send_buf = {{ 0 }}; + socket.send_to(asio::buffer(send_buf), receiver_endpoint); + + boost::array<char, 128> recv_buf; + udp::endpoint sender_endpoint; + size_t len = socket.receive_from( + asio::buffer(recv_buf), sender_endpoint); + + std::cout.write(recv_buf.data(), len); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime5/.gitignore b/3rdparty/asio/src/examples/cpp03/tutorial/daytime5/.gitignore new file mode 100644 index 00000000000..7f06efb3296 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime5/.gitignore @@ -0,0 +1,10 @@ +server +.deps +.dirstamp +*.o +*.obj +*.exe +*.ilk +*.manifest +*.pdb +*.tds diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime5/server.cpp b/3rdparty/asio/src/examples/cpp03/tutorial/daytime5/server.cpp new file mode 100644 index 00000000000..fdf452562d2 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime5/server.cpp @@ -0,0 +1,58 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <ctime> +#include <iostream> +#include <string> +#include <boost/array.hpp> +#include <asio.hpp> + +using asio::ip::udp; + +std::string make_daytime_string() +{ + using namespace std; // For time_t, time and ctime; + time_t now = time(0); + return ctime(&now); +} + +int main() +{ + try + { + asio::io_context io_context; + + udp::socket socket(io_context, udp::endpoint(udp::v4(), 13)); + + for (;;) + { + boost::array<char, 1> recv_buf; + udp::endpoint remote_endpoint; + asio::error_code error; + socket.receive_from(asio::buffer(recv_buf), + remote_endpoint, 0, error); + + if (error && error != asio::error::message_size) + throw asio::system_error(error); + + std::string message = make_daytime_string(); + + asio::error_code ignored_error; + socket.send_to(asio::buffer(message), + remote_endpoint, 0, ignored_error); + } + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime6/.gitignore b/3rdparty/asio/src/examples/cpp03/tutorial/daytime6/.gitignore new file mode 100644 index 00000000000..7f06efb3296 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime6/.gitignore @@ -0,0 +1,10 @@ +server +.deps +.dirstamp +*.o +*.obj +*.exe +*.ilk +*.manifest +*.pdb +*.tds diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime6/server.cpp b/3rdparty/asio/src/examples/cpp03/tutorial/daytime6/server.cpp new file mode 100644 index 00000000000..d67045ff990 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime6/server.cpp @@ -0,0 +1,89 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <ctime> +#include <iostream> +#include <string> +#include <boost/array.hpp> +#include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <asio.hpp> + +using asio::ip::udp; + +std::string make_daytime_string() +{ + using namespace std; // For time_t, time and ctime; + time_t now = time(0); + return ctime(&now); +} + +class udp_server +{ +public: + udp_server(asio::io_context& io_context) + : socket_(io_context, udp::endpoint(udp::v4(), 13)) + { + start_receive(); + } + +private: + void start_receive() + { + socket_.async_receive_from( + asio::buffer(recv_buffer_), remote_endpoint_, + boost::bind(&udp_server::handle_receive, this, + asio::placeholders::error, + asio::placeholders::bytes_transferred)); + } + + void handle_receive(const asio::error_code& error, + std::size_t /*bytes_transferred*/) + { + if (!error || error == asio::error::message_size) + { + boost::shared_ptr<std::string> message( + new std::string(make_daytime_string())); + + socket_.async_send_to(asio::buffer(*message), remote_endpoint_, + boost::bind(&udp_server::handle_send, this, message, + asio::placeholders::error, + asio::placeholders::bytes_transferred)); + + start_receive(); + } + } + + void handle_send(boost::shared_ptr<std::string> /*message*/, + const asio::error_code& /*error*/, + std::size_t /*bytes_transferred*/) + { + } + + udp::socket socket_; + udp::endpoint remote_endpoint_; + boost::array<char, 1> recv_buffer_; +}; + +int main() +{ + try + { + asio::io_context io_context; + udp_server server(io_context); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime7/.gitignore b/3rdparty/asio/src/examples/cpp03/tutorial/daytime7/.gitignore new file mode 100644 index 00000000000..7f06efb3296 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime7/.gitignore @@ -0,0 +1,10 @@ +server +.deps +.dirstamp +*.o +*.obj +*.exe +*.ilk +*.manifest +*.pdb +*.tds diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime7/server.cpp b/3rdparty/asio/src/examples/cpp03/tutorial/daytime7/server.cpp new file mode 100644 index 00000000000..b9dc60558c9 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime7/server.cpp @@ -0,0 +1,158 @@ +// +// server.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <ctime> +#include <iostream> +#include <string> +#include <boost/array.hpp> +#include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <asio.hpp> + +using asio::ip::tcp; +using asio::ip::udp; + +std::string make_daytime_string() +{ + using namespace std; // For time_t, time and ctime; + time_t now = time(0); + return ctime(&now); +} + +class tcp_connection + : public boost::enable_shared_from_this<tcp_connection> +{ +public: + typedef boost::shared_ptr<tcp_connection> pointer; + + static pointer create(asio::io_context& io_context) + { + return pointer(new tcp_connection(io_context)); + } + + tcp::socket& socket() + { + return socket_; + } + + void start() + { + message_ = make_daytime_string(); + + asio::async_write(socket_, asio::buffer(message_), + boost::bind(&tcp_connection::handle_write, shared_from_this())); + } + +private: + tcp_connection(asio::io_context& io_context) + : socket_(io_context) + { + } + + void handle_write() + { + } + + tcp::socket socket_; + std::string message_; +}; + +class tcp_server +{ +public: + tcp_server(asio::io_context& io_context) + : acceptor_(io_context, tcp::endpoint(tcp::v4(), 13)) + { + start_accept(); + } + +private: + void start_accept() + { + tcp_connection::pointer new_connection = + tcp_connection::create(acceptor_.get_executor().context()); + + acceptor_.async_accept(new_connection->socket(), + boost::bind(&tcp_server::handle_accept, this, new_connection, + asio::placeholders::error)); + } + + void handle_accept(tcp_connection::pointer new_connection, + const asio::error_code& error) + { + if (!error) + { + new_connection->start(); + } + + start_accept(); + } + + tcp::acceptor acceptor_; +}; + +class udp_server +{ +public: + udp_server(asio::io_context& io_context) + : socket_(io_context, udp::endpoint(udp::v4(), 13)) + { + start_receive(); + } + +private: + void start_receive() + { + socket_.async_receive_from( + asio::buffer(recv_buffer_), remote_endpoint_, + boost::bind(&udp_server::handle_receive, this, + asio::placeholders::error)); + } + + void handle_receive(const asio::error_code& error) + { + if (!error || error == asio::error::message_size) + { + boost::shared_ptr<std::string> message( + new std::string(make_daytime_string())); + + socket_.async_send_to(asio::buffer(*message), remote_endpoint_, + boost::bind(&udp_server::handle_send, this, message)); + + start_receive(); + } + } + + void handle_send(boost::shared_ptr<std::string> /*message*/) + { + } + + udp::socket socket_; + udp::endpoint remote_endpoint_; + boost::array<char, 1> recv_buffer_; +}; + +int main() +{ + try + { + asio::io_context io_context; + tcp_server server1(io_context); + udp_server server2(io_context); + io_context.run(); + } + catch (std::exception& e) + { + std::cerr << e.what() << std::endl; + } + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/daytime_dox.txt b/3rdparty/asio/src/examples/cpp03/tutorial/daytime_dox.txt new file mode 100644 index 00000000000..1bf591a43a8 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/daytime_dox.txt @@ -0,0 +1,502 @@ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** +\page tutdaytime1 Daytime.1 - A synchronous TCP daytime client + +This tutorial program shows how to use asio to implement a client application +with TCP. + +\dontinclude daytime1/client.cpp +\skip #include + +We start by including the necessary header files. + +\until asio.hpp + +The purpose of this application is to access a daytime service, +so we need the user to specify the server. + +\until } + +All programs that use asio need to have at least one asio::io_service +object. + +\until asio::io_service + +We need to turn the server name that was specified as a parameter to the +application, into a TCP endpoint. To do this we use an +asio::ip::tcp::resolver object. + +\until tcp::resolver + +A resolver takes a query object and turns it into a list of endpoints. We +construct a query using the name of the server, specified in <tt>argv[1]</tt>, +and the name of the service, in this case <tt>"daytime"</tt>. + +\until tcp::resolver::query + +The list of endpoints is returned using an iterator of type +asio::ip::tcp::resolver::iterator. (Note that a default constructed +asio::ip::tcp::resolver::iterator object can be used as an end iterator.) + +\until tcp::resolver::iterator + +Now we create and connect the socket. The list of endpoints obtained above may +contain both IPv4 and IPv6 endpoints, so we need to try each of them until we +find one that works. This keeps the client program independent of a specific IP +version. The asio::connect() function does this for us automatically. + +\until asio::connect + +The connection is open. All we need to do now is read the response from the +daytime service. + +We use a <tt>boost::array</tt> to hold the received data. The asio::buffer() +function automatically determines the size of the array to help prevent buffer +overruns. Instead of a <tt>boost::array</tt>, we could have used a <tt>char +[]</tt> or <tt>std::vector</tt>. + +\until read_some + +When the server closes the connection, the asio::ip::tcp::socket::read_some() +function will exit with the asio::error::eof error, which is how we know to +exit the loop. + +\until } + +Finally, handle any exceptions that may have been thrown. + +\until } +\until } + +See the \ref tutdaytime1src "full source listing" \n +Return to the \ref index "tutorial index" \n +Next: \ref tutdaytime2 + +*/ + +/** +\page tutdaytime1src Source listing for Daytime.1 +\include daytime1/client.cpp +Return to \ref tutdaytime1 +*/ + +/** +\page tutdaytime2 Daytime.2 - A synchronous TCP daytime server + +This tutorial program shows how to use asio to implement a server application +with TCP. + +\dontinclude daytime2/server.cpp +\skip #include + +\until using + +We define the function <tt>make_daytime_string()</tt> to create the string to +be sent back to the client. This function will be reused in all of our daytime +server applications. + +\until asio::io_service + +A asio::ip::tcp::acceptor object needs to be created to listen +for new connections. It is initialised to listen on TCP port 13, for IP version 4. + +\until tcp::acceptor + +This is an iterative server, which means that it will handle one +connection at a time. Create a socket that will represent the connection to the +client, and then wait for a connection. + +\until acceptor.accept + +A client is accessing our service. Determine the current time +and transfer this information to the client. + +\until } +\until } + +Finally, handle any exceptions. + +\until } +\until } + +See the \ref tutdaytime2src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tutdaytime1 \n +Next: \ref tutdaytime3 + +*/ + +/** +\page tutdaytime2src Source listing for Daytime.2 +\include daytime2/server.cpp +Return to \ref tutdaytime2 +*/ + +/** +\page tutdaytime3 Daytime.3 - An asynchronous TCP daytime server + +\section tutdaytime3funcmain The main() function + +\dontinclude daytime3/server.cpp +\skip int main() +\until try +\until { + +We need to create a server object to accept incoming client connections. The +asio::io_service object provides I/O services, such as sockets, that the +server object will use. + +\until tcp_server + +Run the asio::io_service object so that it will perform asynchronous operations +on your behalf. + +\until return 0; +\until } + +\section tutdaytime3classtcp_server The tcp_server class + +\dontinclude daytime3/server.cpp +\skip class tcp_server +\until public: + +The constructor initialises an acceptor to listen on TCP port 13. + +\until private: + +The function <tt>start_accept()</tt> creates a socket and initiates an +asynchronous accept operation to wait for a new connection. + +\until } + +The function <tt>handle_accept()</tt> is called when the asynchronous accept +operation initiated by <tt>start_accept()</tt> finishes. It services the client +request, and then calls <tt>start_accept()</tt> to initiate the next accept +operation. + +\until } +\until } + +\section tutdaytime3classtcp_connection The tcp_connection class + +We will use <tt>shared_ptr</tt> and <tt>enable_shared_from_this</tt> because we +want to keep the <tt>tcp_connection</tt> object alive as long as there is an +operation that refers to it. + +\dontinclude daytime3/server.cpp +\skip class tcp_connection +\until shared_ptr +\until } +\until } + +In the function <tt>start()</tt>, we call asio::async_write() to serve the data +to the client. Note that we are using asio::async_write(), rather than +asio::ip::tcp::socket::async_write_some(), to ensure that the entire block of +data is sent. + +\until { + +The data to be sent is stored in the class member <tt>message_</tt> as we need +to keep the data valid until the asynchronous operation is complete. + +\until message_ + +When initiating the asynchronous operation, and if using \ref boost_bind, you +must specify only the arguments that match the handler's parameter list. In +this program, both of the argument placeholders (asio::placeholders::error and +asio::placeholders::bytes_transferred) could potentially have been removed, +since they are not being used in <tt>handle_write()</tt>. + +\until placeholders::bytes_transferred + +Any further actions for this client connection are now the responsibility of +<tt>handle_write()</tt>. + +\until }; + +\section tutdaytime3remunused Removing unused handler parameters + +You may have noticed that the <tt>error</tt>, and <tt>bytes_transferred</tt> +parameters are not used in the body of the <tt>handle_write()</tt> function. If +parameters are not needed, it is possible to remove them from the function so +that it looks like: + +\code + void handle_write() + { + } +\endcode + +The asio::async_write() call used to initiate the call can then be changed to +just: + +\code + asio::async_write(socket_, asio::buffer(message_), + boost::bind(&tcp_connection::handle_write, shared_from_this())); +\endcode + +See the \ref tutdaytime3src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tutdaytime2 \n +Next: \ref tutdaytime4 + +*/ + +/** +\page tutdaytime3src Source listing for Daytime.3 +\include daytime3/server.cpp +Return to \ref tutdaytime3 +*/ + +/** +\page tutdaytime4 Daytime.4 - A synchronous UDP daytime client + +This tutorial program shows how to use asio to implement a client application +with UDP. + +\dontinclude daytime4/client.cpp +\skip #include +\until using asio::ip::udp; + +The start of the application is essentially the same as for the TCP daytime +client. + +\until asio::io_service + +We use an asio::ip::udp::resolver object to find the correct remote endpoint to +use based on the host and service names. The query is restricted to return only +IPv4 endpoints by the asio::ip::udp::v4() argument. + +\until udp::v4 + +The asio::ip::udp::resolver::resolve() function is guaranteed to return at +least one endpoint in the list if it does not fail. This means it is safe to +dereference the return value directly. + +\until udp::endpoint + +Since UDP is datagram-oriented, we will not be using a stream socket. Create an +asio::ip::udp::socket and initiate contact with the remote endpoint. + +\until receiver_endpoint + +Now we need to be ready to accept whatever the server sends back to us. The +endpoint on our side that receives the server's response will be initialised by +asio::ip::udp::socket::receive_from(). + +\until } + +Finally, handle any exceptions that may have been thrown. + +\until } +\until } +See the \ref tutdaytime4src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tutdaytime3 \n +Next: \ref tutdaytime5 + +*/ + +/** +\page tutdaytime4src Source listing for Daytime.4 +\include daytime4/client.cpp +Return to \ref tutdaytime4 +*/ + +/** +\page tutdaytime5 Daytime.5 - A synchronous UDP daytime server + +This tutorial program shows how to use asio to implement a server application +with UDP. + +\dontinclude daytime5/server.cpp +\skip int main() +\until asio::io_service + +Create an asio::ip::udp::socket object to receive requests on UDP port 13. + +\until udp::socket + +Wait for a client to initiate contact with us. The remote_endpoint object will +be populated by asio::ip::udp::socket::receive_from(). + +\until throw + +Determine what we are going to send back to the client. + +\until std::string message + +Send the response to the remote_endpoint. + +\until } +\until } + +Finally, handle any exceptions. + +\until } +\until } + +See the \ref tutdaytime5src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tutdaytime4 \n +Next: \ref tutdaytime6 + +*/ + +/** +\page tutdaytime5src Source listing for Daytime.5 +\include daytime5/server.cpp +Return to \ref tutdaytime5 +*/ + +/** +\page tutdaytime6 Daytime.6 - An asynchronous UDP daytime server + +\section tutdaytime6funcmain The main() function + +\dontinclude daytime6/server.cpp +\skip int main() +\until try +\until { + +Create a server object to accept incoming client requests, and run +the asio::io_service object. + +\until return 0; +\until } + +\section tutdaytime6classudp_server The udp_server class + +\dontinclude daytime6/server.cpp +\skip class udp_server +\until public: + +The constructor initialises a socket to listen on UDP port 13. + +\until private: +\until { + +The function asio::ip::udp::socket::async_receive_from() will cause the +application to listen in the background for a new request. When such a request +is received, the asio::io_service object will invoke the +<tt>handle_receive()</tt> function with two arguments: a value of type +asio::error_code indicating whether the operation succeeded or failed, and a +<tt>size_t</tt> value <tt>bytes_transferred</tt> specifying the number of bytes +received. + +\until } + +The function <tt>handle_receive()</tt> will service the client request. + +\until { + +The <tt>error</tt> parameter contains the result of the asynchronous operation. +Since we only provide the 1-byte <tt>recv_buffer_</tt> to contain the client's +request, the asio::io_service object would return an error if the client sent +anything larger. We can ignore such an error if it comes up. + +\until { + +Determine what we are going to send. + +\until make_daytime_string() + +We now call asio::ip::udp::socket::async_send_to() to serve the data to the +client. + +\until asio::placeholders::bytes_transferred + +When initiating the asynchronous operation, and if using \ref boost_bind, you +must specify only the arguments that match the handler's parameter list. In +this program, both of the argument placeholders (asio::placeholders::error and +asio::placeholders::bytes_transferred) could potentially have been removed. + +Start listening for the next client request. + +\until start_receive + +Any further actions for this client request are now the responsibility of +<tt>handle_send()</tt>. + +\until } +\until } + +The function <tt>handle_send()</tt> is invoked after the service request has +been completed. + +\until } +\until } + +See the \ref tutdaytime6src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tutdaytime5 \n +Next: \ref tutdaytime7 + +*/ + +/** +\page tutdaytime6src Source listing for Daytime.6 +\include daytime6/server.cpp +Return to \ref tutdaytime6 +*/ + +/** +\page tutdaytime7 Daytime.7 - A combined TCP/UDP asynchronous server + +This tutorial program shows how to combine the two asynchronous servers that we +have just written, into a single server application. + +\section tutdaytime7funcmain The main() function + +\dontinclude daytime7/server.cpp +\skip int main() +\until asio::io_service + +We will begin by creating a server object to accept a TCP client connection. + +\until tcp_server + +We also need a server object to accept a UDP client request. + +\until udp_server + +We have created two lots of work for the asio::io_service object to do. + +\until return 0; +\until } + +\section tutdaytime7classtcp The tcp_connection and tcp_server classes + +The following two classes are taken from \ref tutdaytime3 "Daytime.3". + +\dontinclude daytime7/server.cpp +\skip class tcp_connection +\until }; +\until }; + +\section tutdaytime7classudp The udp_server class + +Similarly, this next class is taken from the +\ref tutdaytime6 "previous tutorial step". + +\dontinclude daytime7/server.cpp +\skip class udp_server +\until }; + +See the \ref tutdaytime7src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tutdaytime6 + +*/ + +/** +\page tutdaytime7src Source listing for Daytime.7 +\include daytime7/server.cpp +Return to \ref tutdaytime7 +*/ diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/index_dox.txt b/3rdparty/asio/src/examples/cpp03/tutorial/index_dox.txt new file mode 100644 index 00000000000..7d3bd1a2912 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/index_dox.txt @@ -0,0 +1,48 @@ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** +\mainpage asio Tutorial + +\section tuttimer Basic Skills + +The tutorial programs in this first section introduce the fundamental concepts +required to use the asio toolkit. Before plunging into the complex world of +network programming, these tutorial programs illustrate the basic skills using +simple asynchronous timers. + +\li \ref tuttimer1 +\li \ref tuttimer2 +\li \ref tuttimer3 +\li \ref tuttimer4 +\li \ref tuttimer5 + +\section tutdaytime Introduction to Sockets + +The tutorial programs in this section show how to use asio to develop simple +client and server programs. These tutorial programs are based around the <a +href="http://www.ietf.org/rfc/rfc867.txt">daytime</a> protocol, which supports +both TCP and UDP. + +The first three tutorial programs implement the daytime protocol using TCP. + +\li \ref tutdaytime1 +\li \ref tutdaytime2 +\li \ref tutdaytime3 + +The next three tutorial programs implement the daytime protocol using UDP. + +\li \ref tutdaytime4 +\li \ref tutdaytime5 +\li \ref tutdaytime6 + +The last tutorial program in this section demonstrates how asio allows the TCP +and UDP servers to be easily combined into a single program. + +\li \ref tutdaytime7 + +*/ diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/timer1/.gitignore b/3rdparty/asio/src/examples/cpp03/tutorial/timer1/.gitignore new file mode 100644 index 00000000000..1d47ca67c43 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/timer1/.gitignore @@ -0,0 +1,10 @@ +timer +.deps +.dirstamp +*.o +*.obj +*.exe +*.ilk +*.manifest +*.pdb +*.tds diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/timer1/timer.cpp b/3rdparty/asio/src/examples/cpp03/tutorial/timer1/timer.cpp new file mode 100644 index 00000000000..79ddf918261 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/timer1/timer.cpp @@ -0,0 +1,25 @@ +// +// timer.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <asio.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> + +int main() +{ + asio::io_context io; + + asio::deadline_timer t(io, boost::posix_time::seconds(5)); + t.wait(); + + std::cout << "Hello, world!" << std::endl; + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/timer2/.gitignore b/3rdparty/asio/src/examples/cpp03/tutorial/timer2/.gitignore new file mode 100644 index 00000000000..1d47ca67c43 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/timer2/.gitignore @@ -0,0 +1,10 @@ +timer +.deps +.dirstamp +*.o +*.obj +*.exe +*.ilk +*.manifest +*.pdb +*.tds diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/timer2/timer.cpp b/3rdparty/asio/src/examples/cpp03/tutorial/timer2/timer.cpp new file mode 100644 index 00000000000..3275c22c2f6 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/timer2/timer.cpp @@ -0,0 +1,30 @@ +// +// timer.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <asio.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> + +void print(const asio::error_code& /*e*/) +{ + std::cout << "Hello, world!" << std::endl; +} + +int main() +{ + asio::io_context io; + + asio::deadline_timer t(io, boost::posix_time::seconds(5)); + t.async_wait(&print); + + io.run(); + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/timer3/.gitignore b/3rdparty/asio/src/examples/cpp03/tutorial/timer3/.gitignore new file mode 100644 index 00000000000..1d47ca67c43 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/timer3/.gitignore @@ -0,0 +1,10 @@ +timer +.deps +.dirstamp +*.o +*.obj +*.exe +*.ilk +*.manifest +*.pdb +*.tds diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/timer3/timer.cpp b/3rdparty/asio/src/examples/cpp03/tutorial/timer3/timer.cpp new file mode 100644 index 00000000000..dfbf7d660a0 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/timer3/timer.cpp @@ -0,0 +1,44 @@ +// +// timer.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <asio.hpp> +#include <boost/bind.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> + +void print(const asio::error_code& /*e*/, + asio::deadline_timer* t, int* count) +{ + if (*count < 5) + { + std::cout << *count << std::endl; + ++(*count); + + t->expires_at(t->expires_at() + boost::posix_time::seconds(1)); + t->async_wait(boost::bind(print, + asio::placeholders::error, t, count)); + } +} + +int main() +{ + asio::io_context io; + + int count = 0; + asio::deadline_timer t(io, boost::posix_time::seconds(1)); + t.async_wait(boost::bind(print, + asio::placeholders::error, &t, &count)); + + io.run(); + + std::cout << "Final count is " << count << std::endl; + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/timer4/.gitignore b/3rdparty/asio/src/examples/cpp03/tutorial/timer4/.gitignore new file mode 100644 index 00000000000..1d47ca67c43 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/timer4/.gitignore @@ -0,0 +1,10 @@ +timer +.deps +.dirstamp +*.o +*.obj +*.exe +*.ilk +*.manifest +*.pdb +*.tds diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/timer4/timer.cpp b/3rdparty/asio/src/examples/cpp03/tutorial/timer4/timer.cpp new file mode 100644 index 00000000000..cbea70d26fa --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/timer4/timer.cpp @@ -0,0 +1,55 @@ +// +// timer.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <asio.hpp> +#include <boost/bind.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> + +class printer +{ +public: + printer(asio::io_context& io) + : timer_(io, boost::posix_time::seconds(1)), + count_(0) + { + timer_.async_wait(boost::bind(&printer::print, this)); + } + + ~printer() + { + std::cout << "Final count is " << count_ << std::endl; + } + + void print() + { + if (count_ < 5) + { + std::cout << count_ << std::endl; + ++count_; + + timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1)); + timer_.async_wait(boost::bind(&printer::print, this)); + } + } + +private: + asio::deadline_timer timer_; + int count_; +}; + +int main() +{ + asio::io_context io; + printer p(io); + io.run(); + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/timer5/.gitignore b/3rdparty/asio/src/examples/cpp03/tutorial/timer5/.gitignore new file mode 100644 index 00000000000..1d47ca67c43 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/timer5/.gitignore @@ -0,0 +1,10 @@ +timer +.deps +.dirstamp +*.o +*.obj +*.exe +*.ilk +*.manifest +*.pdb +*.tds diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/timer5/timer.cpp b/3rdparty/asio/src/examples/cpp03/tutorial/timer5/timer.cpp new file mode 100644 index 00000000000..a798e85aacf --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/timer5/timer.cpp @@ -0,0 +1,81 @@ +// +// timer.cpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <iostream> +#include <asio.hpp> +#include <boost/bind.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> + +class printer +{ +public: + printer(asio::io_context& io) + : strand_(io), + timer1_(io, boost::posix_time::seconds(1)), + timer2_(io, boost::posix_time::seconds(1)), + count_(0) + { + timer1_.async_wait(asio::bind_executor(strand_, + boost::bind(&printer::print1, this))); + + timer2_.async_wait(asio::bind_executor(strand_, + boost::bind(&printer::print2, this))); + } + + ~printer() + { + std::cout << "Final count is " << count_ << std::endl; + } + + void print1() + { + if (count_ < 10) + { + std::cout << "Timer 1: " << count_ << std::endl; + ++count_; + + timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(1)); + + timer1_.async_wait(asio::bind_executor(strand_, + boost::bind(&printer::print1, this))); + } + } + + void print2() + { + if (count_ < 10) + { + std::cout << "Timer 2: " << count_ << std::endl; + ++count_; + + timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1)); + + timer2_.async_wait(asio::bind_executor(strand_, + boost::bind(&printer::print2, this))); + } + } + +private: + asio::io_context::strand strand_; + asio::deadline_timer timer1_; + asio::deadline_timer timer2_; + int count_; +}; + +int main() +{ + asio::io_context io; + printer p(io); + asio::thread t(boost::bind(&asio::io_context::run, &io)); + io.run(); + t.join(); + + return 0; +} diff --git a/3rdparty/asio/src/examples/cpp03/tutorial/timer_dox.txt b/3rdparty/asio/src/examples/cpp03/tutorial/timer_dox.txt new file mode 100644 index 00000000000..7c5a0a099a6 --- /dev/null +++ b/3rdparty/asio/src/examples/cpp03/tutorial/timer_dox.txt @@ -0,0 +1,383 @@ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +/** +\page tuttimer1 Timer.1 - Using a timer synchronously + +This tutorial program introduces asio by showing how to perform a blocking +wait on a timer. + +\dontinclude timer1/timer.cpp +\skip #include + +We start by including the necessary header files. + +All of the asio classes can be used by simply including the <tt>"asio.hpp"</tt> +header file. + +\until asio.hpp + +Since this example uses timers, we need to include the appropriate +Boost.Date_Time header file for manipulating times. + +\until posix_time.hpp + +All programs that use asio need to have at least one asio::io_service object. +This class provides access to I/O functionality. We declare an object of this +type first thing in the main function. + +\until asio::io_service + +Next we declare an object of type asio::deadline_timer. The core asio classes +that provide I/O functionality (or as in this case timer functionality) always +take a reference to an io_service as their first constructor argument. The +second argument to the constructor sets the timer to expire 5 seconds from now. + +\until asio::deadline_timer + +In this simple example we perform a blocking wait on the timer. +That is, the call to asio::deadline_timer::wait() will not return until the +timer has expired, 5 seconds after it was created (i.e. <b>not</b> from when the +wait starts). + +A deadline timer is always in one of two states: "expired" or "not expired". If +the asio::deadline_timer::wait() function is called on an expired timer, it +will return immediately. + +\until wait + +Finally we print the obligatory <tt>"Hello, world!"</tt> +message to show when the timer has expired. + +\until } + +See the \ref tuttimer1src "full source listing" \n +Return to the \ref index "tutorial index" \n +Next: \ref tuttimer2 + +*/ + +/** +\page tuttimer1src Source listing for Timer.1 +\include timer1/timer.cpp +Return to \ref tuttimer1 +*/ + +/** +\page tuttimer2 Timer.2 - Using a timer asynchronously + +This tutorial program demonstrates how to use asio's asynchronous callback +functionality by modifying the program from tutorial Timer.1 to perform an +asynchronous wait on the timer. + +\dontinclude timer2/timer.cpp +\skip #include + +\until posix_time.hpp + +Using asio's asynchronous functionality means having a callback +function that will be called when an asynchronous operation completes. In this +program we define a function called <tt>print</tt> to be called when the +asynchronous wait finishes. + +\until asio::deadline_timer + +Next, instead of doing a blocking wait as in tutorial Timer.1, +we call the asio::deadline_timer::async_wait() function to perform an +asynchronous wait. When calling this function we pass the <tt>print</tt> +callback handler that was defined above. + +\skipline async_wait + +Finally, we must call the asio::io_service::run() member function +on the io_service object. + +The asio library provides a guarantee that callback handlers will <b>only</b> +be called from threads that are currently calling asio::io_service::run(). +Therefore unless the asio::io_service::run() function is called the callback for +the asynchronous wait completion will never be invoked. + +The asio::io_service::run() function will also continue to run while there is +still "work" to do. In this example, the work is the asynchronous wait on the +timer, so the call will not return until the timer has expired and the +callback has completed. + +It is important to remember to give the io_service some work to do before +calling asio::io_service::run(). For example, if we had omitted the above call +to asio::deadline_timer::async_wait(), the io_service would not have had any +work to do, and consequently asio::io_service::run() would have returned +immediately. + +\skip run +\until } + +See the \ref tuttimer2src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tuttimer1 \n +Next: \ref tuttimer3 + +*/ + +/** +\page tuttimer2src Source listing for Timer.2 +\include timer2/timer.cpp +Return to \ref tuttimer2 +*/ + +/** +\page tuttimer3 Timer.3 - Binding arguments to a handler + +In this tutorial we will modify the program from tutorial Timer.2 so that the +timer fires once a second. This will show how to pass additional parameters to +your handler function. + +\dontinclude timer3/timer.cpp +\skip #include + +\until posix_time.hpp + +To implement a repeating timer using asio you need to change +the timer's expiry time in your callback function, and to then start a new +asynchronous wait. Obviously this means that the callback function will need +to be able to access the timer object. To this end we add two new parameters +to the <tt>print</tt> function: + +\li A pointer to a timer object. + +\li A counter so that we can stop the program when the timer fires for the +sixth time. + +\until { + +As mentioned above, this tutorial program uses a counter to +stop running when the timer fires for the sixth time. However you will observe +that there is no explicit call to ask the io_service to stop. Recall that in +tutorial Timer.2 we learnt that the asio::io_service::run() function completes +when there is no more "work" to do. By not starting a new asynchronous wait on +the timer when <tt>count</tt> reaches 5, the io_service will run out of work and +stop running. + +\until ++ + +Next we move the expiry time for the timer along by one second +from the previous expiry time. By calculating the new expiry time relative to +the old, we can ensure that the timer does not drift away from the +whole-second mark due to any delays in processing the handler. + +\until expires_at + +Then we start a new asynchronous wait on the timer. As you can +see, the \ref boost_bind function is used to associate the extra parameters +with your callback handler. The asio::deadline_timer::async_wait() function +expects a handler function (or function object) with the signature +<tt>void(const asio::error_code&)</tt>. Binding the additional parameters +converts your <tt>print</tt> function into a function object that matches the +signature correctly. + +See the <a href="http://www.boost.org/libs/bind/bind.html">Boost.Bind +documentation</a> for more information on how to use \ref boost_bind. + +In this example, the asio::placeholders::error argument to \ref boost_bind is a +named placeholder for the error object passed to the handler. When initiating +the asynchronous operation, and if using \ref boost_bind, you must specify only +the arguments that match the handler's parameter list. In tutorial Timer.4 you +will see that this placeholder may be elided if the parameter is not needed by +the callback handler. + +\until asio::io_service + +A new <tt>count</tt> variable is added so that we can stop the +program when the timer fires for the sixth time. + +\until asio::deadline_timer + +As in Step 4, when making the call to +asio::deadline_timer::async_wait() from <tt>main</tt> we bind the additional +parameters needed for the <tt>print</tt> function. + +\until run + +Finally, just to prove that the <tt>count</tt> variable was +being used in the <tt>print</tt> handler function, we will print out its new +value. + +\until } + +See the \ref tuttimer3src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tuttimer2 \n +Next: \ref tuttimer4 + +*/ + +/** +\page tuttimer3src Source listing for Timer.3 +\include timer3/timer.cpp +Return to \ref tuttimer3 +*/ + +/** +\page tuttimer4 Timer.4 - Using a member function as a handler + +In this tutorial we will see how to use a class member function as a callback +handler. The program should execute identically to the tutorial program from +tutorial Timer.3. + +\dontinclude timer4/timer.cpp +\skip #include + +\until posix_time.hpp + +Instead of defining a free function <tt>print</tt> as the +callback handler, as we did in the earlier tutorial programs, we now define a +class called <tt>printer</tt>. + +\until public + +The constructor of this class will take a reference to the +io_service object and use it when initialising the <tt>timer_</tt> member. The +counter used to shut down the program is now also a member of the class. + +\until { + +The \ref boost_bind function works just as well with class +member functions as with free functions. Since all non-static class member +functions have an implicit <tt>this</tt> parameter, we need to bind +<tt>this</tt> to the function. As in tutorial Timer.3, \ref boost_bind +converts our callback handler (now a member function) into a function object +that can be invoked as though it has the signature <tt>void(const +asio::error_code&)</tt>. + +You will note that the asio::placeholders::error placeholder is not specified +here, as the <tt>print</tt> member function does not accept an error object as +a parameter. + +\until } + +In the class destructor we will print out the final value of +the counter. + +\until } + +The <tt>print</tt> member function is very similar to the +<tt>print</tt> function from tutorial Timer.3, except that it now operates on +the class data members instead of having the timer and counter passed in as +parameters. + +\until }; + +The <tt>main</tt> function is much simpler than before, as it +now declares a local <tt>printer</tt> object before running the io_service as +normal. + +\until } + +See the \ref tuttimer4src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tuttimer3 \n +Next: \ref tuttimer5 \n + +*/ + +/** +\page tuttimer4src Source listing for Timer.4 +\include timer4/timer.cpp +Return to \ref tuttimer4 +*/ + +/** +\page tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs + +This tutorial demonstrates the use of the asio::io_service::strand class to +synchronise callback handlers in a multithreaded program. + +The previous four tutorials avoided the issue of handler synchronisation by +calling the asio::io_service::run() function from one thread only. As you +already know, the asio library provides a guarantee that callback handlers will +<b>only</b> be called from threads that are currently calling +asio::io_service::run(). Consequently, calling asio::io_service::run() from +only one thread ensures that callback handlers cannot run concurrently. + +The single threaded approach is usually the best place to start when +developing applications using asio. The downside is the limitations it places +on programs, particularly servers, including: + +<ul> +<li>Poor responsiveness when handlers can take a long time to complete.</li> +<li>An inability to scale on multiprocessor systems.</li> +</ul> + +If you find yourself running into these limitations, an alternative approach +is to have a pool of threads calling asio::io_service::run(). However, as this +allows handlers to execute concurrently, we need a method of synchronisation +when handlers might be accessing a shared, thread-unsafe resource. + +\dontinclude timer5/timer.cpp +\skip #include + +\until posix_time.hpp + +We start by defining a class called <tt>printer</tt>, similar +to the class in the previous tutorial. This class will extend the previous +tutorial by running two timers in parallel. + +\until public + +In addition to initialising a pair of asio::deadline_timer members, the +constructor initialises the <tt>strand_</tt> member, an object of type +asio::io_service::strand. + +An asio::io_service::strand is an executor that guarantees that, for those +handlers that are dispatched through it, an executing handler will be allowed +to complete before the next one is started. This is guaranteed irrespective of +the number of threads that are calling asio::io_service::run(). Of course, the +handlers may still execute concurrently with other handlers that were +<b>not</b> dispatched through an asio::io_service::strand, or were dispatched +through a different asio::io_service::strand object. + +\until { + +When initiating the asynchronous operations, each callback handler is "bound" +to an asio::io_service::strand object. The +asio::io_service::strand::bind_executor() function returns a new handler that +automatically dispatches its contained handler through the +asio::io_service::strand object. By binding the handlers to the same +asio::io_service::strand, we are ensuring that they cannot execute +concurrently. + +\until } +\until } + +In a multithreaded program, the handlers for asynchronous +operations should be synchronised if they access shared resources. In this +tutorial, the shared resources used by the handlers (<tt>print1</tt> and +<tt>print2</tt>) are <tt>std::cout</tt> and the <tt>count_</tt> data member. + +\until }; + +The <tt>main</tt> function now causes asio::io_service::run() to +be called from two threads: the main thread and one additional thread. This is +accomplished using an asio::thread object. + +Just as it would with a call from a single thread, concurrent calls to +asio::io_service::run() will continue to execute while there is "work" left to +do. The background thread will not exit until all asynchronous operations have +completed. + +\until } + +See the \ref tuttimer5src "full source listing" \n +Return to the \ref index "tutorial index" \n +Previous: \ref tuttimer4 \n + +*/ + +/** +\page tuttimer5src Source listing for Timer.5 +\include timer5/timer.cpp +Return to \ref tuttimer5 +*/ |