tutdaytime3.html
9.48 KB
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Daytime.3 - An asynchronous TCP daytime server</title>
<link rel="stylesheet" href="../../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.2">
<link rel="home" href="../../index.html" title="Asio">
<link rel="up" href="../tutorial.html" title="Tutorial">
<link rel="prev" href="tutdaytime2/src.html" title="Source listing for Daytime.2">
<link rel="next" href="tutdaytime3/src.html" title="Source listing for Daytime.3">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr><td valign="top"><img alt="asio C++ library" width="250" height="60" src="../../asio.png"></td></tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="tutdaytime2/src.html"><img src="../../prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.html"><img src="../../up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../home.png" alt="Home"></a><a accesskey="n" href="tutdaytime3/src.html"><img src="../../next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="asio.tutorial.tutdaytime3"></a><a class="link" href="tutdaytime3.html" title="Daytime.3 - An asynchronous TCP daytime server">Daytime.3 - An asynchronous
TCP daytime server</a>
</h3></div></div></div>
<h5>
<a name="asio.tutorial.tutdaytime3.h0"></a>
<span><a name="asio.tutorial.tutdaytime3.the_main___function"></a></span><a class="link" href="tutdaytime3.html#asio.tutorial.tutdaytime3.the_main___function">The
main() function</a>
</h5>
<pre class="programlisting">int main()
{
try
{
</pre>
<p>
We need to create a server object to accept incoming client connections.
The <a class="link" href="../reference/io_context.html" title="io_context">io_context</a> object provides
I/O services, such as sockets, that the server object will use.
</p>
<pre class="programlisting"> asio::io_context io_context;
tcp_server server(io_context);
</pre>
<p>
Run the <a class="link" href="../reference/io_context.html" title="io_context">io_context</a> object
so that it will perform asynchronous operations on your behalf.
</p>
<pre class="programlisting"> io_context.run();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
</pre>
<h5>
<a name="asio.tutorial.tutdaytime3.h1"></a>
<span><a name="asio.tutorial.tutdaytime3.the_tcp_server_class"></a></span><a class="link" href="tutdaytime3.html#asio.tutorial.tutdaytime3.the_tcp_server_class">The
tcp_server class</a>
</h5>
<pre class="programlisting">class tcp_server
{
public:
</pre>
<p>
The constructor initialises an acceptor to listen on TCP port 13.
</p>
<pre class="programlisting"> tcp_server(asio::io_context& io_context)
: io_context_(io_context),
acceptor_(io_context, tcp::endpoint(tcp::v4(), 13))
{
start_accept();
}
private:
</pre>
<p>
The function <code class="computeroutput">start_accept()</code> creates a socket and initiates an
asynchronous accept operation to wait for a new connection.
</p>
<pre class="programlisting"> void start_accept()
{
tcp_connection::pointer new_connection =
tcp_connection::create(io_context_);
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
asio::placeholders::error));
}
</pre>
<p>
The function <code class="computeroutput">handle_accept()</code> is called when the asynchronous
accept operation initiated by <code class="computeroutput">start_accept()</code> finishes. It services
the client request, and then calls <code class="computeroutput">start_accept()</code> to initiate
the next accept operation.
</p>
<pre class="programlisting"> void handle_accept(tcp_connection::pointer new_connection,
const asio::error_code& error)
{
if (!error)
{
new_connection->start();
}
start_accept();
}
</pre>
<h5>
<a name="asio.tutorial.tutdaytime3.h2"></a>
<span><a name="asio.tutorial.tutdaytime3.the_tcp_connection_class"></a></span><a class="link" href="tutdaytime3.html#asio.tutorial.tutdaytime3.the_tcp_connection_class">The
tcp_connection class</a>
</h5>
<p>
We will use <code class="computeroutput">shared_ptr</code> and <code class="computeroutput">enable_shared_from_this</code>
because we want to keep the <code class="computeroutput">tcp_connection</code> object alive as long
as there is an operation that refers to it.
</p>
<pre class="programlisting">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_;
}
</pre>
<p>
In the function <code class="computeroutput">start()</code>, we call asio::async_write() to serve
the data to the client. Note that we are using asio::async_write(), rather
than <a class="link" href="../reference/basic_stream_socket/async_write_some.html" title="basic_stream_socket::async_write_some">ip::tcp::socket::async_write_some()</a>,
to ensure that the entire block of data is sent.
</p>
<pre class="programlisting"> void start()
{
</pre>
<p>
The data to be sent is stored in the class member <code class="computeroutput">message_</code> as
we need to keep the data valid until the asynchronous operation is complete.
</p>
<pre class="programlisting"> message_ = make_daytime_string();
</pre>
<p>
When initiating the asynchronous operation, and if using <a class="link" href="boost_bind.html" title="boost::bind">boost::bind</a>
, 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 <code class="computeroutput">handle_write()</code>.
</p>
<pre class="programlisting"> asio::async_write(socket_, asio::buffer(message_),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
asio::placeholders::error,
asio::placeholders::bytes_transferred));
</pre>
<p>
Any further actions for this client connection are now the responsibility
of <code class="computeroutput">handle_write()</code>.
</p>
<pre class="programlisting"> }
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_;
};
</pre>
<h5>
<a name="asio.tutorial.tutdaytime3.h3"></a>
<span><a name="asio.tutorial.tutdaytime3.removing_unused_handler_parameters"></a></span><a class="link" href="tutdaytime3.html#asio.tutorial.tutdaytime3.removing_unused_handler_parameters">Removing
unused handler parameters</a>
</h5>
<p>
You may have noticed that the <code class="computeroutput">error</code>, and <code class="computeroutput">bytes_transferred</code>
parameters are not used in the body of the <code class="computeroutput">handle_write()</code> function.
If parameters are not needed, it is possible to remove them from the function
so that it looks like:
</p>
<pre class="programlisting"> void handle_write()
{
}
</pre>
<p>
The asio::async_write() call used to initiate the call can then be changed
to just:
</p>
<pre class="programlisting"> asio::async_write(socket_, asio::buffer(message_),
boost::bind(&tcp_connection::handle_write, shared_from_this()));
</pre>
<p>
See the <a class="link" href="tutdaytime3/src.html" title="Source listing for Daytime.3">full source listing</a>
</p>
<p>
Return to the <a class="link" href="../tutorial.html" title="Tutorial">tutorial index</a>
</p>
<p>
Previous: <a class="link" href="tutdaytime2.html" title="Daytime.2 - A synchronous TCP daytime server">Daytime.2 - A synchronous
TCP daytime server</a>
</p>
<p>
Next: <a class="link" href="tutdaytime4.html" title="Daytime.4 - A synchronous UDP daytime client">Daytime.4 - A synchronous
UDP daytime client</a>
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright © 2003-2020 Christopher M.
Kohlhoff<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="tutdaytime2/src.html"><img src="../../prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.html"><img src="../../up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../home.png" alt="Home"></a><a accesskey="n" href="tutdaytime3/src.html"><img src="../../next.png" alt="Next"></a>
</div>
</body>
</html>