-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathasync_server.cpp
150 lines (126 loc) · 4.63 KB
/
async_server.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// from
// https://www.bogotobogo.com/cplusplus/sockets_server_client.php
// https://www.bogotobogo.com/cplusplus/Boost/files/asioD/async_server.cpp
//
// Synchronous TCP server
//
// This sample code shows how to use asio to implement a server application
// with TCP. An asynchronous TCP daytime server
// TODO: deprecated! boost::asio::io_service
// tcp::acceptor::get_io_service/get_io_context
// FIXME #define BOOST_ASIO_NO_DEPRECATED
#include <boost/config.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <ctime>
#include <iostream>
#include <string>
using boost::asio::ip::tcp;
std::string make_daytime_string()
{
std::time_t now = std::time(0);
return std::ctime(&now);
}
class tcp_connection
// NOTE: Using 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.
: public boost::enable_shared_from_this<tcp_connection> {
public:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_context& io_service)
{
return pointer(new tcp_connection(io_service));
}
tcp::socket& socket() { return socket_; }
// Call boost::asio::async_write() to serve the data to the client.
// We are using boost::asio::async_write(),
// rather than 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 m_message
// as we need to keep the data valid
// until the asynchronous operation is complete.
m_message = make_daytime_string();
// When initiating the asynchronous operation,
// and if using boost::bind(),
// we must specify only the arguments
// that match the handler's parameter list.
// In this code, 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(m_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_service)
: socket_(io_service)
{ }
// handle_write() is responsible for any further actions
// for this client connection.
void handle_write(const boost::system::error_code& /*error*/,
size_t /*bytes_transferred*/)
{ }
tcp::socket socket_;
std::string m_message;
};
class tcp_server {
public:
// Constructor: initialises an acceptor to listen on TCP port 13.
tcp_server(boost::asio::io_context& io_service)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), 13))
{
// start_accept() creates a socket and
// initiates an asynchronous accept operation
// to wait for a new connection.
start_accept();
}
private:
void start_accept()
{
// creates a socket
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_context());
// initiates an asynchronous accept operation
// to wait for a new connection.
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
}
// handle_accept() is called when the asynchronous accept operation
// initiated by start_accept() finishes. It services the client request
void handle_accept(tcp_connection::pointer new_connection,
const boost::system::error_code& error)
{
if (!error) {
new_connection->start();
}
// Call start_accept() to initiate the next accept operation.
start_accept();
}
tcp::acceptor acceptor_;
};
int main()
{
try {
// We need to create a server object to accept incoming client
// connections.
boost::asio::io_context io_service;
// The io_service object provides I/O services, such as sockets,
// that the server object will use.
tcp_server server(io_service);
// Run the io_service object to perform asynchronous operations.
io_service.run();
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
// TODO return 1;
}
return 0;
}