[/ / Copyright (c) 2003-2008 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) /] [library Boost.Asio [quickbook 1.4] [copyright 2003 - 2008 Christopher M. Kohlhoff] [license 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]) ] [category generic] ] [section:tutorial Tutorial] [section:tuttimer4 Timer.4 - Using a member function as a handler] [section:src Source listing for Timer.4] ``''''''``// ``''''''``// timer.cpp ``''''''``// ~~~~~~~~~ ``''''''``// ``''''''``// Copyright (c) 2003-2008 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 ``''''''``#include ``''''''``#include ``''''''``#include ``''''''``class printer ``''''''``{ ``''''''``public: ``''''''`` printer(boost::asio::io_service& 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_ << "\n"; ``''''''`` } ``''''''`` void print() ``''''''`` { ``''''''`` if (count_ < 5) ``''''''`` { ``''''''`` std::cout << count_ << "\n"; ``''''''`` ++count_; ``''''''`` timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1)); ``''''''`` timer_.async_wait(boost::bind(&printer::print, this)); ``''''''`` } ``''''''`` } ``''''''``private: ``''''''`` boost::asio::deadline_timer timer_; ``''''''`` int count_; ``''''''``}; ``''''''``int main() ``''''''``{ ``''''''`` boost::asio::io_service io; ``''''''`` printer p(io); ``''''''`` io.run(); ``''''''`` return 0; ``''''''``} [endsect] [endsect] [section:tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs] If you find yourself running into these limitations, an alternative approach is to have a pool of threads calling boost::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. ``''''''``#include ``''''''``#include ``''''''``#include ``''''''``#include ``''''''``#include When initiating the asynchronous operations, each callback handler is "wrapped" using the boost::asio::strand object. The boost::asio::strand::wrap() function returns a new handler that automatically dispatches its contained handler through the boost::asio::strand object. By wrapping the handlers using the same boost::asio::strand, we are ensuring that they cannot execute concurrently. ``''''''`` timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this))); ``''''''`` timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this))); ``''''''`` } ``''''''`` ~printer() ``''''''`` { ``''''''`` std::cout << "Final count is " << count_ << "\n"; ``''''''`` } 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 (`print1` and `print2`) are `std::cout` and the `count_` data member. ``''''''`` void print1() ``''''''`` { ``''''''`` if (count_ < 10) ``''''''`` { ``''''''`` std::cout << "Timer 1: " << count_ << "\n"; ``''''''`` ++count_; ``''''''`` timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(1)); ``''''''`` timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this))); ``''''''`` } ``''''''`` } ``''''''`` void print2() ``''''''`` { ``''''''`` if (count_ < 10) ``''''''`` { ``''''''`` std::cout << "Timer 2: " << count_ << "\n"; ``''''''`` ++count_; ``''''''`` timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1)); ``''''''`` timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this))); ``''''''`` } ``''''''`` } ``''''''``private: ``''''''`` boost::asio::strand strand_; ``''''''`` boost::asio::deadline_timer timer1_; ``''''''`` boost::asio::deadline_timer timer2_; ``''''''`` int count_; ``''''''``}; The `main` function now causes boost::asio::io\_service::run() to be called from two threads: the main thread and one additional thread. This is accomplished using an boost::thread object. Just as it would with a call from a single thread, concurrent calls to boost::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. ``''''''``int main() ``''''''``{ ``''''''`` boost::asio::io_service io; ``''''''`` printer p(io); ``''''''`` boost::thread t(boost::bind(&boost::asio::io_service::run, &io)); ``''''''`` io.run(); ``''''''`` t.join(); ``''''''`` return 0; ``''''''``} [section:src Source listing for Timer.5] [endsect] [endsect] [section:tutdaytime1 Daytime.1 - A synchronous TCP daytime client] This tutorial program shows how to use asio to implement a client application with TCP. We start by including the necessary header files. ``''''''``#include ``''''''``#include ``''''''``#include The purpose of this application is to access a daytime service, so we need the user to specify the server. ``''''''``using boost::asio::ip::tcp; ``''''''``int main(int argc, char* argv[]) ``''''''``{ ``''''''`` try ``''''''`` { ``''''''`` if (argc != 2) ``''''''`` { ``''''''`` std::cerr << "Usage: client " << std::endl; ``''''''`` return 1; ``''''''`` } All programs that use asio need to have at least one boost::asio::io\_service object. ``''''''`` boost::asio::io_service 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 boost::asio::ip::tcp::resolver object. ``''''''`` tcp::resolver resolver(io_service); 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 `argv[1]`, and the name of the service, in this case `"daytime"`. ``''''''`` tcp::resolver::query query(argv[1], "daytime"); The list of endpoints is returned using an iterator of type boost::asio::ip::tcp::resolver::iterator. A default constructed boost::asio::ip::tcp::resolver::iterator object is used as the end iterator. ``''''''`` tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); ``''''''`` tcp::resolver::iterator end; 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. ``''''''`` tcp::socket socket(io_service); ``''''''`` boost::system::error_code error = boost::asio::error::host_not_found; ``''''''`` while (error && endpoint_iterator != end) ``''''''`` { ``''''''`` socket.close(); ``''''''`` socket.connect(*endpoint_iterator++, error); ``''''''`` } ``''''''`` if (error) ``''''''`` throw boost::system::system_error(error); The connection is open. All we need to do now is read the response from the daytime service. We use a `boost::array` to hold the received data. The boost::asio::buffer() function automatically determines the size of the array to help prevent buffer overruns. Instead of a `boost::array`, we could have used a `char []` or `std::vector`. ``''''''`` for (;;) ``''''''`` { ``''''''`` boost::array buf; ``''''''`` boost::system::error_code error; ``''''''`` size_t len = socket.read_some(boost::asio::buffer(buf), error); When the server closes the connection, the boost::asio::ip::tcp::socket::read\_some() function will exit with the boost::asio::error::eof error, which is how we know to exit the loop. ``''''''`` if (error == boost::asio::error::eof) ``''''''`` break; // Connection closed cleanly by peer. ``''''''`` else if (error) ``''''''`` throw boost::system::system_error(error); // Some other error. ``''''''`` std::cout.write(buf.data(), len); ``''''''`` } Finally, handle any exceptions that may have been thrown. ``''''''`` } ``''''''`` catch (std::exception& e) ``''''''`` { ``''''''`` std::cerr << e.what() << std::endl; ``''''''`` } See the [link boost_asio.tutorial.tutdaytime1.src full source listing] Return to the [link boost_asio.tutorial tutorial index] Next: [link boost_asio.tutorial.tutdaytime2 Daytime.2 - A synchronous TCP daytime server] [section:src Source listing for Daytime.1] ``''''''``// ``''''''``// client.cpp ``''''''``// ~~~~~~~~~~ ``''''''``// ``''''''``// Copyright (c) 2003-2008 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 ``''''''``#include ``''''''``#include ``''''''``using boost::asio::ip::tcp; ``''''''``int main(int argc, char* argv[]) ``''''''``{ ``''''''`` try ``''''''`` { ``''''''`` if (argc != 2) ``''''''`` { ``''''''`` std::cerr << "Usage: client " << std::endl; ``''''''`` return 1; ``''''''`` } ``''''''`` boost::asio::io_service io_service; ``''''''`` tcp::resolver resolver(io_service); ``''''''`` tcp::resolver::query query(argv[1], "daytime"); ``''''''`` tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); ``''''''`` tcp::resolver::iterator end; ``''''''`` tcp::socket socket(io_service); ``''''''`` boost::system::error_code error = boost::asio::error::host_not_found; ``''''''`` while (error && endpoint_iterator != end) ``''''''`` { ``''''''`` socket.close(); ``''''''`` socket.connect(*endpoint_iterator++, error); ``''''''`` } ``''''''`` if (error) ``''''''`` throw boost::system::system_error(error); ``''''''`` for (;;) ``''''''`` { ``''''''`` boost::array buf; ``''''''`` boost::system::error_code error; ``''''''`` size_t len = socket.read_some(boost::asio::buffer(buf), error); ``''''''`` if (error == boost::asio::error::eof) ``''''''`` break; // Connection closed cleanly by peer. ``''''''`` else if (error) ``''''''`` throw boost::system::system_error(error); // Some other error. ``''''''`` std::cout.write(buf.data(), len); ``''''''`` } ``''''''`` } ``''''''`` catch (std::exception& e) ``''''''`` { ``''''''`` std::cerr << e.what() << std::endl; ``''''''`` } ``''''''`` return 0; ``''''''``} Return to [link boost_asio.tutorial.tutdaytime1 Daytime.1 - A synchronous TCP daytime client] [endsect] [endsect] [section:tutdaytime2 Daytime.2 - A synchronous TCP daytime server] This tutorial program shows how to use asio to implement a server application with TCP. ``''''''``#include ``''''''``#include ``''''''``#include ``''''''``#include ``''''''``using boost::asio::ip::tcp; We define the function `make_daytime_string()` to create the string to be sent back to the client. This function will be reused in all of our daytime server applications. ``''''''``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 ``''''''`` { ``''''''`` boost::asio::io_service io_service; A boost::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. ``''''''`` tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 13)); 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. ``''''''`` for (;;) ``''''''`` { ``''''''`` tcp::socket socket(io_service); ``''''''`` acceptor.accept(socket); A client is accessing our service. Determine the current time and transfer this information to the client. ``''''''`` std::string message = make_daytime_string(); ``''''''`` boost::system::error_code ignored_error; ``''''''`` boost::asio::write(socket, boost::asio::buffer(message), ``''''''`` boost::asio::transfer_all(), ignored_error); ``''''''`` } ``''''''`` } Finally, handle any exceptions. ``''''''`` catch (std::exception& e) ``''''''`` { ``''''''`` std::cerr << e.what() << std::endl; ``''''''`` } ``''''''`` return 0; ``''''''``} See the [link boost_asio.tutorial.tutdaytime2.src full source listing] Return to the [link boost_asio.tutorial tutorial index] Previous: [link boost_asio.tutorial.tutdaytime1 Daytime.1 - A synchronous TCP daytime client] Next: [link boost_asio.tutorial.tutdaytime3 Daytime.3 - An asynchronous TCP daytime server] [section:src Source listing for Daytime.2] ``''''''``// ``''''''``// server.cpp ``''''''``// ~~~~~~~~~~ ``''''''``// ``''''''``// Copyright (c) 2003-2008 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 ``''''''``#include ``''''''``#include ``''''''``#include ``''''''``using boost::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 ``''''''`` { ``''''''`` boost::asio::io_service io_service; ``''''''`` tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 13)); ``''''''`` for (;;) ``''''''`` { ``''''''`` tcp::socket socket(io_service); ``''''''`` acceptor.accept(socket); ``''''''`` std::string message = make_daytime_string(); ``''''''`` boost::system::error_code ignored_error; ``''''''`` boost::asio::write(socket, boost::asio::buffer(message), ``''''''`` boost::asio::transfer_all(), ignored_error); ``''''''`` } ``''''''`` } ``''''''`` catch (std::exception& e) ``''''''`` { ``''''''`` std::cerr << e.what() << std::endl; ``''''''`` } ``''''''`` return 0; ``''''''``} Return to [link boost_asio.tutorial.tutdaytime2 Daytime.2 - A synchronous TCP daytime server] [endsect] [endsect] [section:tutdaytime3 Daytime.3 - An asynchronous TCP daytime server] [heading The main() function] ``''''''``int main() ``''''''``{ ``''''''`` try ``''''''`` { We need to create a server object to accept incoming client connections. The boost::asio::io\_service object provides I/O services, such as sockets, that the server object will use. ``''''''`` boost::asio::io_service io_service; ``''''''`` tcp_server server(io_service); Run the boost::asio::io\_service object so that it will perform asynchronous operations on your behalf. ``''''''`` io_service.run(); ``''''''`` } ``''''''`` catch (std::exception& e) ``''''''`` { ``''''''`` std::cerr << e.what() << std::endl; ``''''''`` } ``''''''`` return 0; ``''''''``} [heading The tcp_server class] ``''''''``class tcp_server ``''''''``{ ``''''''``public: The constructor initialises an acceptor to listen on TCP port 13. ``''''''`` tcp_server(boost::asio::io_service& io_service) ``''''''`` : acceptor_(io_service, tcp::endpoint(tcp::v4(), 13)) ``''''''`` { ``''''''`` start_accept(); ``''''''`` } ``''''''``private: The function `start_accept()` creates a socket and initiates an asynchronous accept operation to wait for a new connection. ``''''''`` void start_accept() ``''''''`` { ``''''''`` tcp_connection::pointer new_connection = ``''''''`` tcp_connection::create(acceptor_.io_service()); ``''''''`` acceptor_.async_accept(new_connection->socket(), ``''''''`` boost::bind(&tcp_server::handle_accept, this, new_connection, ``''''''`` boost::asio::placeholders::error)); ``''''''`` } The function `handle_accept()` is called when the asynchronous accept operation initiated by `start_accept()` finishes. It services the client request, and then calls `start_accept()` to initiate the next accept operation. ``''''''`` void handle_accept(tcp_connection::pointer new_connection, ``''''''`` const boost::system::error_code& error) ``''''''`` { ``''''''`` if (!error) ``''''''`` { ``''''''`` new_connection->start(); ``''''''`` start_accept(); ``''''''`` } ``''''''`` } [heading The tcp_connection class] We will use `shared_ptr` and `enable_shared_from_this` because we want to keep the `tcp_connection` object alive as long as there is an operation that refers to it. ``''''''``class tcp_connection ``''''''`` : public boost::enable_shared_from_this ``''''''``{ ``''''''``public: ``''''''`` typedef boost::shared_ptr pointer; ``''''''`` static pointer create(boost::asio::io_service& io_service) ``''''''`` { ``''''''`` return pointer(new tcp_connection(io_service)); ``''''''`` } ``''''''`` tcp::socket& socket() ``''''''`` { ``''''''`` return socket_; ``''''''`` } In the function `start()`, we call boost::asio::async\_write() to serve the data to the client. Note that we are using boost::asio::async\_write(), rather than boost::asio::ip::tcp::socket::async\_write\_some(), to ensure that the entire block of data is sent. ``''''''`` void start() ``''''''`` { The data to be sent is stored in the class member `message_` as we need to keep the data valid until the asynchronous operation is complete. ``''''''`` message_ = make_daytime_string(); When initiating the asynchronous operation, and if using boost::bind(), you must specify only the arguments that match the handler's parameter list. In this program, both of the argument placeholders (boost::asio::placeholders::error and boost::asio::placeholders::bytes\_transferred) could potentially have been removed, since they are not being used in `handle_write()`. ``''''''`` boost::asio::async_write(socket_, boost::asio::buffer(message_), ``''''''`` boost::bind(&tcp_connection::handle_write, shared_from_this(), ``''''''`` boost::asio::placeholders::error, ``''''''`` boost::asio::placeholders::bytes_transferred)); Any further actions for this client connection are now the responsibility of `handle_write()`. ``''''''`` } ``''''''``private: ``''''''`` tcp_connection(boost::asio::io_service& io_service) ``''''''`` : socket_(io_service) ``''''''`` { ``''''''`` } ``''''''`` void handle_write(const boost::system::error_code& /*error*/, ``''''''`` size_t /*bytes_transferred*/) ``''''''`` { ``''''''`` } ``''''''`` tcp::socket socket_; ``''''''`` std::string message_; ``''''''``}; [heading Removing unused handler parameters] You may have noticed that the `error`, and `bytes_transferred` parameters are not used in the body of the `handle_write()` function. If parameters are not needed, it is possible to remove them from the function so that it looks like: ``''''''`` void handle_write() ``''''''`` { ``''''''`` } The boost::asio::async\_write() call used to initiate the call can then be changed to just: ``''''''`` boost::asio::async_write(socket_, boost::asio::buffer(message_), ``''''''`` boost::bind(&tcp_connection::handle_write, shared_from_this())); See the [link boost_asio.tutorial.tutdaytime3.src full source listing] Return to the [link boost_asio.tutorial tutorial index] Previous: [link boost_asio.tutorial.tutdaytime2 Daytime.2 - A synchronous TCP daytime server] Next: [link boost_asio.tutorial.tutdaytime4 Daytime.4 - A synchronous UDP daytime client] [section:src Source listing for Daytime.3] ``''''''``// ``''''''``// server.cpp ``''''''``// ~~~~~~~~~~ ``''''''``// ``''''''``// Copyright (c) 2003-2008 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 ``''''''``#include ``''''''``#include ``''''''``#include ``''''''``#include ``''''''``#include ``''''''``#include ``''''''``using boost::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 ``''''''``{ ``''''''``public: ``''''''`` typedef boost::shared_ptr pointer; ``''''''`` static pointer create(boost::asio::io_service& io_service) ``''''''`` { ``''''''`` return pointer(new tcp_connection(io_service)); ``''''''`` } ``''''''`` tcp::socket& socket() ``''''''`` { ``''''''`` return socket_; ``''''''`` } ``''''''`` void start() ``''''''`` { ``''''''`` message_ = make_daytime_string(); ``''''''`` boost::asio::async_write(socket_, boost::asio::buffer(message_), ``''''''`` boost::bind(&tcp_connection::handle_write, shared_from_this(), ``''''''`` boost::asio::placeholders::error, ``''''''`` boost::asio::placeholders::bytes_transferred)); ``''''''`` } ``''''''``private: ``''''''`` tcp_connection(boost::asio::io_service& io_service) ``''''''`` : socket_(io_service) ``''''''`` { ``''''''`` } ``''''''`` void handle_write(const boost::system::error_code& /*error*/, ``''''''`` size_t /*bytes_transferred*/) ``''''''`` { ``''''''`` } ``''''''`` tcp::socket socket_; ``''''''`` std::string message_; ``''''''``}; ``''''''``class tcp_server ``''''''``{ ``''''''``public: ``''''''`` tcp_server(boost::asio::io_service& io_service) ``''''''`` : acceptor_(io_service, tcp::endpoint(tcp::v4(), 13)) ``''''''`` { ``''''''`` start_accept(); ``''''''`` } ``''''''``private: ``''''''`` void start_accept() ``''''''`` { ``''''''`` tcp_connection::pointer new_connection = ``''''''`` tcp_connection::create(acceptor_.io_service()); ``''''''`` acceptor_.async_accept(new_connection->socket(), ``''''''`` boost::bind(&tcp_server::handle_accept, this, new_connection, ``''''''`` boost::asio::placeholders::error)); ``''''''`` } ``''''''`` void handle_accept(tcp_connection::pointer new_connection, ``''''''`` const boost::system::error_code& error) ``''''''`` { ``''''''`` if (!error) ``''''''`` { ``''''''`` new_connection->start(); ``''''''`` start_accept(); ``''''''`` } ``''''''`` } ``''''''`` tcp::acceptor acceptor_; ``''''''``}; ``''''''``int main() ``''''''``{ ``''''''`` try ``''''''`` { ``''''''`` boost::asio::io_service io_service; ``''''''`` tcp_server server(io_service); ``''''''`` io_service.run(); ``''''''`` } ``''''''`` catch (std::exception& e) ``''''''`` { ``''''''`` std::cerr << e.what() << std::endl; ``''''''`` } ``''''''`` return 0; ``''''''``} Return to [link boost_asio.tutorial.tutdaytime3 Daytime.3 - An asynchronous TCP daytime server] [endsect] [endsect] [section:tutdaytime4 Daytime.4 - A synchronous UDP daytime client] This tutorial program shows how to use asio to implement a client application with UDP. ``''''''``#include ``''''''``#include ``''''''``#include ``''''''``using boost::asio::ip::udp; The start of the application is essentially the same as for the TCP daytime client. ``''''''``int main(int argc, char* argv[]) ``''''''``{ ``''''''`` try ``''''''`` { ``''''''`` if (argc != 2) ``''''''`` { ``''''''`` std::cerr << "Usage: client " << std::endl; ``''''''`` return 1; ``''''''`` } ``''''''`` boost::asio::io_service io_service; We use an boost::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 boost::asio::ip::udp::v4() argument. ``''''''`` udp::resolver resolver(io_service); ``''''''`` udp::resolver::query query(udp::v4(), argv[1], "daytime"); The boost::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. ``''''''`` udp::endpoint receiver_endpoint = *resolver.resolve(query); Since UDP is datagram-oriented, we will not be using a stream socket. Create an boost::asio::ip::udp::socket and initiate contact with the remote endpoint. ``''''''`` udp::socket socket(io_service); ``''''''`` socket.open(udp::v4()); ``''''''`` boost::array send_buf = { 0 }; ``''''''`` socket.send_to(boost::asio::buffer(send_buf), 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 boost::asio::ip::udp::socket::receive\_from(). ``''''''`` boost::array recv_buf; ``''''''`` udp::endpoint sender_endpoint; ``''''''`` size_t len = socket.receive_from( ``''''''`` boost::asio::buffer(recv_buf), sender_endpoint); ``''''''`` std::cout.write(recv_buf.data(), len); ``''''''`` } Finally, handle any exceptions that may have been thrown. ``''''''`` catch (std::exception& e) ``''''''`` { ``''''''`` std::cerr << e.what() << std::endl; ``''''''`` } ``''''''`` return 0; ``''''''``} See the [link boost_asio.tutorial.tutdaytime4.src full source listing] Return to the [link boost_asio.tutorial tutorial index] Previous: [link boost_asio.tutorial.tutdaytime3 Daytime.3 - An asynchronous TCP daytime server] Next: [link boost_asio.tutorial.tutdaytime5 Daytime.5 - A synchronous UDP daytime server] [endsect] [endsect]