2 // posix_chat_client.cpp
3 // ~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2014 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_service& io_service,
28 tcp::resolver::iterator endpoint_iterator)
29 : socket_(io_service),
30 input_(io_service, ::dup(STDIN_FILENO)),
31 output_(io_service, ::dup(STDOUT_FILENO)),
32 input_buffer_(chat_message::max_body_length)
34 boost::asio::async_connect(socket_, endpoint_iterator,
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_service io_service;
187 tcp::resolver resolver(io_service);
188 tcp::resolver::query query(argv[1], argv[2]);
189 tcp::resolver::iterator iterator = resolver.resolve(query);
191 posix_chat_client c(io_service, iterator);
195 catch (std::exception& e)
197 std::cerr << "Exception: " << e.what() << "\n";
203 #else // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
205 #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)