2 // posix_chat_client.cpp
3 // ~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
14 #include <boost/array.hpp>
15 #include <boost/bind.hpp>
16 #include <boost/asio.hpp>
17 #include "chat_message.hpp"
19 #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
21 using boost::asio::ip::tcp
;
22 namespace posix
= boost::asio::posix
;
24 class posix_chat_client
27 posix_chat_client(boost::asio::io_context
& io_context
,
28 const tcp::resolver::results_type
& endpoints
)
29 : socket_(io_context
),
30 input_(io_context
, ::dup(STDIN_FILENO
)),
31 output_(io_context
, ::dup(STDOUT_FILENO
)),
32 input_buffer_(chat_message::max_body_length
)
34 boost::asio::async_connect(socket_
, endpoints
,
35 boost::bind(&posix_chat_client::handle_connect
, this,
36 boost::asio::placeholders::error
));
41 void handle_connect(const boost::system::error_code
& error
)
45 // Read the fixed-length header of the next message from the server.
46 boost::asio::async_read(socket_
,
47 boost::asio::buffer(read_msg_
.data(), chat_message::header_length
),
48 boost::bind(&posix_chat_client::handle_read_header
, this,
49 boost::asio::placeholders::error
));
51 // Read a line of input entered by the user.
52 boost::asio::async_read_until(input_
, input_buffer_
, '\n',
53 boost::bind(&posix_chat_client::handle_read_input
, this,
54 boost::asio::placeholders::error
,
55 boost::asio::placeholders::bytes_transferred
));
59 void handle_read_header(const boost::system::error_code
& error
)
61 if (!error
&& read_msg_
.decode_header())
63 // Read the variable-length body of the message from the server.
64 boost::asio::async_read(socket_
,
65 boost::asio::buffer(read_msg_
.body(), read_msg_
.body_length()),
66 boost::bind(&posix_chat_client::handle_read_body
, this,
67 boost::asio::placeholders::error
));
75 void handle_read_body(const boost::system::error_code
& error
)
79 // Write out the message we just received, terminated by a newline.
80 static char eol
[] = { '\n' };
81 boost::array
<boost::asio::const_buffer
, 2> buffers
= {{
82 boost::asio::buffer(read_msg_
.body(), read_msg_
.body_length()),
83 boost::asio::buffer(eol
) }};
84 boost::asio::async_write(output_
, buffers
,
85 boost::bind(&posix_chat_client::handle_write_output
, this,
86 boost::asio::placeholders::error
));
94 void handle_write_output(const boost::system::error_code
& error
)
98 // Read the fixed-length header of the next message from the server.
99 boost::asio::async_read(socket_
,
100 boost::asio::buffer(read_msg_
.data(), chat_message::header_length
),
101 boost::bind(&posix_chat_client::handle_read_header
, this,
102 boost::asio::placeholders::error
));
110 void handle_read_input(const boost::system::error_code
& error
,
115 // Write the message (minus the newline) to the server.
116 write_msg_
.body_length(length
- 1);
117 input_buffer_
.sgetn(write_msg_
.body(), length
- 1);
118 input_buffer_
.consume(1); // Remove newline from input.
119 write_msg_
.encode_header();
120 boost::asio::async_write(socket_
,
121 boost::asio::buffer(write_msg_
.data(), write_msg_
.length()),
122 boost::bind(&posix_chat_client::handle_write
, this,
123 boost::asio::placeholders::error
));
125 else if (error
== boost::asio::error::not_found
)
127 // Didn't get a newline. Send whatever we have.
128 write_msg_
.body_length(input_buffer_
.size());
129 input_buffer_
.sgetn(write_msg_
.body(), input_buffer_
.size());
130 write_msg_
.encode_header();
131 boost::asio::async_write(socket_
,
132 boost::asio::buffer(write_msg_
.data(), write_msg_
.length()),
133 boost::bind(&posix_chat_client::handle_write
, this,
134 boost::asio::placeholders::error
));
142 void handle_write(const boost::system::error_code
& error
)
146 // Read a line of input entered by the user.
147 boost::asio::async_read_until(input_
, input_buffer_
, '\n',
148 boost::bind(&posix_chat_client::handle_read_input
, this,
149 boost::asio::placeholders::error
,
150 boost::asio::placeholders::bytes_transferred
));
160 // Cancel all outstanding asynchronous operations.
168 posix::stream_descriptor input_
;
169 posix::stream_descriptor output_
;
170 chat_message read_msg_
;
171 chat_message write_msg_
;
172 boost::asio::streambuf input_buffer_
;
175 int main(int argc
, char* argv
[])
181 std::cerr
<< "Usage: posix_chat_client <host> <port>\n";
185 boost::asio::io_context io_context
;
187 tcp::resolver
resolver(io_context
);
188 tcp::resolver::results_type endpoints
= resolver
.resolve(argv
[1], argv
[2]);
190 posix_chat_client
c(io_context
, endpoints
);
194 catch (std::exception
& e
)
196 std::cerr
<< "Exception: " << e
.what() << "\n";
202 #else // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
204 #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)