[DEV] add v1.66.0

This commit is contained in:
2018-01-12 21:47:58 +01:00
parent 87059bb1af
commit a97e9ae7d4
49032 changed files with 7668950 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
#
# Copyright (c) 2003-2017 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)
#
import os ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
project
: requirements
<library>/boost/system//boost_system
<library>/boost/thread//boost_thread
<define>BOOST_ALL_NO_LIB=1
<threading>multi
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
;
obj timer1.obj : timer1/timer.cpp ;
exe timer1 : timer1.obj ;
obj timer2.obj : timer2/timer.cpp ;
exe timer2 : timer2.obj ;
obj timer3.obj : timer3/timer.cpp ;
exe timer3 : timer3.obj ;
obj timer4.obj : timer4/timer.cpp ;
exe timer4 : timer4.obj ;
obj timer5.obj : timer5/timer.cpp ;
exe timer5 : timer5.obj ;
obj daytime1_client.obj : daytime1/client.cpp ;
exe daytime1_client : daytime1_client.obj ;
obj daytime2_server.obj : daytime2/server.cpp ;
exe daytime2_server : daytime2_server.obj ;
obj daytime3_server.obj : daytime3/server.cpp ;
exe daytime3_server : daytime3_server.obj ;
obj daytime4_client.obj : daytime4/client.cpp ;
exe daytime4_client : daytime4_client.obj ;
obj daytime5_server.obj : daytime5/server.cpp ;
exe daytime5_server : daytime5_server.obj ;
obj daytime6_server.obj : daytime6/server.cpp ;
exe daytime6_server : daytime6_server.obj ;
obj daytime7_server.obj : daytime7/server.cpp ;
exe daytime7_server : daytime7_server.obj ;

View File

@@ -0,0 +1,57 @@
//
// client.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2017 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 <boost/asio.hpp>
using boost::asio::ip::tcp;
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: client <host>" << std::endl;
return 1;
}
boost::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);
boost::asio::connect(socket, endpoints);
for (;;)
{
boost::array<char, 128> 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;
}

View File

@@ -0,0 +1,50 @@
//
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2017 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/asio.hpp>
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_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();
boost::system::error_code ignored_error;
boost::asio::write(socket, boost::asio::buffer(message), ignored_error);
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}

View File

@@ -0,0 +1,117 @@
//
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2017 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 <boost/asio.hpp>
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<tcp_connection>
{
public:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_context& io_context)
{
return pointer(new tcp_connection(io_context));
}
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_context& io_context)
: socket_(io_context)
{
}
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_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,
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_context io_context;
tcp_server server(io_context);
io_context.run();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}

View File

@@ -0,0 +1,52 @@
//
// client.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2017 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 <boost/asio.hpp>
using boost::asio::ip::udp;
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: client <host>" << std::endl;
return 1;
}
boost::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(boost::asio::buffer(send_buf), receiver_endpoint);
boost::array<char, 128> 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);
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}

View File

@@ -0,0 +1,54 @@
//
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2017 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/asio.hpp>
using boost::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
{
boost::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;
boost::system::error_code error;
socket.receive_from(boost::asio::buffer(recv_buf), remote_endpoint);
std::string message = make_daytime_string();
boost::system::error_code ignored_error;
socket.send_to(boost::asio::buffer(message),
remote_endpoint, 0, ignored_error);
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}

View File

@@ -0,0 +1,89 @@
//
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2017 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/asio.hpp>
using boost::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(boost::asio::io_context& io_context)
: socket_(io_context, udp::endpoint(udp::v4(), 13))
{
start_receive();
}
private:
void start_receive()
{
socket_.async_receive_from(
boost::asio::buffer(recv_buffer_), remote_endpoint_,
boost::bind(&udp_server::handle_receive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void handle_receive(const boost::system::error_code& error,
std::size_t /*bytes_transferred*/)
{
if (!error)
{
boost::shared_ptr<std::string> message(
new std::string(make_daytime_string()));
socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_,
boost::bind(&udp_server::handle_send, this, message,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
start_receive();
}
}
void handle_send(boost::shared_ptr<std::string> /*message*/,
const boost::system::error_code& /*error*/,
std::size_t /*bytes_transferred*/)
{
}
udp::socket socket_;
udp::endpoint remote_endpoint_;
boost::array<char, 1> recv_buffer_;
};
int main()
{
try
{
boost::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;
}

View File

@@ -0,0 +1,158 @@
//
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2017 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 <boost/asio.hpp>
using boost::asio::ip::tcp;
using boost::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(boost::asio::io_context& io_context)
{
return pointer(new tcp_connection(io_context));
}
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()));
}
private:
tcp_connection(boost::asio::io_context& io_context)
: socket_(io_context)
{
}
void handle_write()
{
}
tcp::socket socket_;
std::string message_;
};
class tcp_server
{
public:
tcp_server(boost::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,
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_;
};
class udp_server
{
public:
udp_server(boost::asio::io_context& io_context)
: socket_(io_context, udp::endpoint(udp::v4(), 13))
{
start_receive();
}
private:
void start_receive()
{
socket_.async_receive_from(
boost::asio::buffer(recv_buffer_), remote_endpoint_,
boost::bind(&udp_server::handle_receive, this,
boost::asio::placeholders::error));
}
void handle_receive(const boost::system::error_code& error)
{
if (!error)
{
boost::shared_ptr<std::string> message(
new std::string(make_daytime_string()));
socket_.async_send_to(boost::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
{
boost::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;
}

View File

@@ -0,0 +1,502 @@
//
// Copyright (c) 2003-2017 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 boost::asio::io_service
object.
\until boost::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
boost::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
boost::asio::ip::tcp::resolver::iterator. (Note that a default constructed
boost::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 boost::asio::connect() function does this for us automatically.
\until boost::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 boost::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 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.
\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 boost::asio::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.
\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
boost::asio::io_service object provides I/O services, such as sockets, that the
server object will use.
\until tcp_server
Run the boost::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 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.
\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 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 <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 boost::asio::async_write() call used to initiate the call can then be changed to
just:
\code
boost::asio::async_write(socket_, boost::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 boost::asio::ip::udp;
The start of the application is essentially the same as for the TCP daytime
client.
\until boost::asio::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.
\until udp::v4
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.
\until udp::endpoint
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.
\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
boost::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 boost::asio::io_service
Create an boost::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 boost::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 boost::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 boost::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 boost::asio::io_service object will invoke the
<tt>handle_receive()</tt> function with two arguments: a value of type
boost::system::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 boost::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 boost::asio::ip::udp::socket::async_send_to() to serve the data to the
client.
\until boost::asio::placeholders::bytes_transferred
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.
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 boost::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 boost::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
*/

View File

@@ -0,0 +1,48 @@
//
// Copyright (c) 2003-2017 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
*/

View File

@@ -0,0 +1,25 @@
//
// timer.cpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2017 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/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
int main()
{
boost::asio::io_context io;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
t.wait();
std::cout << "Hello, world!" << std::endl;
return 0;
}

View File

@@ -0,0 +1,30 @@
//
// timer.cpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2017 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/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
void print(const boost::system::error_code& /*e*/)
{
std::cout << "Hello, world!" << std::endl;
}
int main()
{
boost::asio::io_context io;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
t.async_wait(&print);
io.run();
return 0;
}

View File

@@ -0,0 +1,44 @@
//
// timer.cpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2017 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/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
void print(const boost::system::error_code& /*e*/,
boost::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,
boost::asio::placeholders::error, t, count));
}
}
int main()
{
boost::asio::io_context io;
int count = 0;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));
t.async_wait(boost::bind(print,
boost::asio::placeholders::error, &t, &count));
io.run();
std::cout << "Final count is " << count << std::endl;
return 0;
}

View File

@@ -0,0 +1,55 @@
//
// timer.cpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2017 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/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
class printer
{
public:
printer(boost::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:
boost::asio::deadline_timer timer_;
int count_;
};
int main()
{
boost::asio::io_context io;
printer p(io);
io.run();
return 0;
}

View File

@@ -0,0 +1,82 @@
//
// timer.cpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2017 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/asio.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
class printer
{
public:
printer(boost::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(boost::asio::bind_executor(strand_,
boost::bind(&printer::print1, this)));
timer2_.async_wait(boost::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(boost::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(boost::asio::bind_executor(strand_,
boost::bind(&printer::print2, this)));
}
}
private:
boost::asio::io_context::strand strand_;
boost::asio::deadline_timer timer1_;
boost::asio::deadline_timer timer2_;
int count_;
};
int main()
{
boost::asio::io_context io;
printer p(io);
boost::thread t(boost::bind(&boost::asio::io_context::run, &io));
io.run();
t.join();
return 0;
}

View File

@@ -0,0 +1,383 @@
//
// Copyright (c) 2003-2017 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 boost::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 boost::asio::io_service
Next we declare an object of type boost::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 boost::asio::deadline_timer
In this simple example we perform a blocking wait on the timer.
That is, the call to boost::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 boost::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 boost::asio::deadline_timer
Next, instead of doing a blocking wait as in tutorial Timer.1,
we call the boost::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 boost::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 boost::asio::io_service::run().
Therefore unless the boost::asio::io_service::run() function is called the callback for
the asynchronous wait completion will never be invoked.
The boost::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 boost::asio::io_service::run(). For example, if we had omitted the above call
to boost::asio::deadline_timer::async_wait(), the io_service would not have had any
work to do, and consequently boost::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 boost::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 boost::bind() function is used to associate the extra parameters
with your callback handler. The boost::asio::deadline_timer::async_wait() function
expects a handler function (or function object) with the signature
<tt>void(const boost::system::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 boost::bind().
In this example, the boost::asio::placeholders::error argument to boost::bind() is a
named placeholder for the error object passed to the handler. When initiating
the asynchronous operation, and if using 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 boost::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 boost::asio::deadline_timer
As in Step 4, when making the call to
boost::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 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, 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
boost::system::error_code&)</tt>.
You will note that the boost::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 boost::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 boost::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
boost::asio::io_service::run(). Consequently, calling boost::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 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.
\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 boost::asio::deadline_timer members, the
constructor initialises the <tt>strand_</tt> member, an object of type
boost::asio::io_service::strand.
An boost::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 boost::asio::io_service::run(). Of course, the
handlers may still execute concurrently with other handlers that were
<b>not</b> dispatched through an boost::asio::io_service::strand, or were dispatched
through a different boost::asio::io_service::strand object.
\until {
When initiating the asynchronous operations, each callback handler is "bound"
to an boost::asio::io_service::strand object. The
boost::asio::io_service::strand::bind_executor() function returns a new handler that
automatically dispatches its contained handler through the
boost::asio::io_service::strand object. By binding the handlers to the same
boost::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 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.
\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
*/