summaryrefslogtreecommitdiff
path: root/doc/html/boost_asio/example/cpp03/chat
diff options
context:
space:
mode:
Diffstat (limited to 'doc/html/boost_asio/example/cpp03/chat')
-rw-r--r--doc/html/boost_asio/example/cpp03/chat/chat_client.cpp177
-rw-r--r--doc/html/boost_asio/example/cpp03/chat/chat_message.hpp93
-rw-r--r--doc/html/boost_asio/example/cpp03/chat/chat_server.cpp247
-rw-r--r--doc/html/boost_asio/example/cpp03/chat/posix_chat_client.cpp205
4 files changed, 722 insertions, 0 deletions
diff --git a/doc/html/boost_asio/example/cpp03/chat/chat_client.cpp b/doc/html/boost_asio/example/cpp03/chat/chat_client.cpp
new file mode 100644
index 0000000000..71bd50d6d2
--- /dev/null
+++ b/doc/html/boost_asio/example/cpp03/chat/chat_client.cpp
@@ -0,0 +1,177 @@
+//
+// chat_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 <cstdlib>
+#include <deque>
+#include <iostream>
+#include <boost/bind.hpp>
+#include <boost/asio.hpp>
+#include <boost/thread/thread.hpp>
+#include "chat_message.hpp"
+
+using boost::asio::ip::tcp;
+
+typedef std::deque<chat_message> chat_message_queue;
+
+class chat_client
+{
+public:
+ chat_client(boost::asio::io_service& io_service,
+ tcp::resolver::iterator endpoint_iterator)
+ : io_service_(io_service),
+ socket_(io_service)
+ {
+ boost::asio::async_connect(socket_, endpoint_iterator,
+ boost::bind(&chat_client::handle_connect, this,
+ boost::asio::placeholders::error));
+ }
+
+ void write(const chat_message& msg)
+ {
+ io_service_.post(boost::bind(&chat_client::do_write, this, msg));
+ }
+
+ void close()
+ {
+ io_service_.post(boost::bind(&chat_client::do_close, this));
+ }
+
+private:
+
+ void handle_connect(const boost::system::error_code& error)
+ {
+ if (!error)
+ {
+ boost::asio::async_read(socket_,
+ boost::asio::buffer(read_msg_.data(), chat_message::header_length),
+ boost::bind(&chat_client::handle_read_header, this,
+ boost::asio::placeholders::error));
+ }
+ }
+
+ void handle_read_header(const boost::system::error_code& error)
+ {
+ if (!error && read_msg_.decode_header())
+ {
+ boost::asio::async_read(socket_,
+ boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
+ boost::bind(&chat_client::handle_read_body, this,
+ boost::asio::placeholders::error));
+ }
+ else
+ {
+ do_close();
+ }
+ }
+
+ void handle_read_body(const boost::system::error_code& error)
+ {
+ if (!error)
+ {
+ std::cout.write(read_msg_.body(), read_msg_.body_length());
+ std::cout << "\n";
+ boost::asio::async_read(socket_,
+ boost::asio::buffer(read_msg_.data(), chat_message::header_length),
+ boost::bind(&chat_client::handle_read_header, this,
+ boost::asio::placeholders::error));
+ }
+ else
+ {
+ do_close();
+ }
+ }
+
+ void do_write(chat_message msg)
+ {
+ bool write_in_progress = !write_msgs_.empty();
+ write_msgs_.push_back(msg);
+ if (!write_in_progress)
+ {
+ boost::asio::async_write(socket_,
+ boost::asio::buffer(write_msgs_.front().data(),
+ write_msgs_.front().length()),
+ boost::bind(&chat_client::handle_write, this,
+ boost::asio::placeholders::error));
+ }
+ }
+
+ void handle_write(const boost::system::error_code& error)
+ {
+ if (!error)
+ {
+ write_msgs_.pop_front();
+ if (!write_msgs_.empty())
+ {
+ boost::asio::async_write(socket_,
+ boost::asio::buffer(write_msgs_.front().data(),
+ write_msgs_.front().length()),
+ boost::bind(&chat_client::handle_write, this,
+ boost::asio::placeholders::error));
+ }
+ }
+ else
+ {
+ do_close();
+ }
+ }
+
+ void do_close()
+ {
+ socket_.close();
+ }
+
+private:
+ boost::asio::io_service& io_service_;
+ tcp::socket socket_;
+ chat_message read_msg_;
+ chat_message_queue write_msgs_;
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 3)
+ {
+ std::cerr << "Usage: chat_client <host> <port>\n";
+ return 1;
+ }
+
+ boost::asio::io_service io_service;
+
+ tcp::resolver resolver(io_service);
+ tcp::resolver::query query(argv[1], argv[2]);
+ tcp::resolver::iterator iterator = resolver.resolve(query);
+
+ chat_client c(io_service, iterator);
+
+ boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));
+
+ char line[chat_message::max_body_length + 1];
+ while (std::cin.getline(line, chat_message::max_body_length + 1))
+ {
+ using namespace std; // For strlen and memcpy.
+ chat_message msg;
+ msg.body_length(strlen(line));
+ memcpy(msg.body(), line, msg.body_length());
+ msg.encode_header();
+ c.write(msg);
+ }
+
+ c.close();
+ t.join();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/doc/html/boost_asio/example/cpp03/chat/chat_message.hpp b/doc/html/boost_asio/example/cpp03/chat/chat_message.hpp
new file mode 100644
index 0000000000..75d31ab993
--- /dev/null
+++ b/doc/html/boost_asio/example/cpp03/chat/chat_message.hpp
@@ -0,0 +1,93 @@
+//
+// chat_message.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// 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)
+//
+
+#ifndef CHAT_MESSAGE_HPP
+#define CHAT_MESSAGE_HPP
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+class chat_message
+{
+public:
+ enum { header_length = 4 };
+ enum { max_body_length = 512 };
+
+ chat_message()
+ : body_length_(0)
+ {
+ }
+
+ const char* data() const
+ {
+ return data_;
+ }
+
+ char* data()
+ {
+ return data_;
+ }
+
+ size_t length() const
+ {
+ return header_length + body_length_;
+ }
+
+ const char* body() const
+ {
+ return data_ + header_length;
+ }
+
+ char* body()
+ {
+ return data_ + header_length;
+ }
+
+ size_t body_length() const
+ {
+ return body_length_;
+ }
+
+ void body_length(size_t new_length)
+ {
+ body_length_ = new_length;
+ if (body_length_ > max_body_length)
+ body_length_ = max_body_length;
+ }
+
+ bool decode_header()
+ {
+ using namespace std; // For strncat and atoi.
+ char header[header_length + 1] = "";
+ strncat(header, data_, header_length);
+ body_length_ = atoi(header);
+ if (body_length_ > max_body_length)
+ {
+ body_length_ = 0;
+ return false;
+ }
+ return true;
+ }
+
+ void encode_header()
+ {
+ using namespace std; // For sprintf and memcpy.
+ char header[header_length + 1] = "";
+ sprintf(header, "%4d", static_cast<int>(body_length_));
+ memcpy(data_, header, header_length);
+ }
+
+private:
+ char data_[header_length + max_body_length];
+ size_t body_length_;
+};
+
+#endif // CHAT_MESSAGE_HPP
diff --git a/doc/html/boost_asio/example/cpp03/chat/chat_server.cpp b/doc/html/boost_asio/example/cpp03/chat/chat_server.cpp
new file mode 100644
index 0000000000..611db89243
--- /dev/null
+++ b/doc/html/boost_asio/example/cpp03/chat/chat_server.cpp
@@ -0,0 +1,247 @@
+//
+// chat_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 <algorithm>
+#include <cstdlib>
+#include <deque>
+#include <iostream>
+#include <list>
+#include <set>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <boost/asio.hpp>
+#include "chat_message.hpp"
+
+using boost::asio::ip::tcp;
+
+//----------------------------------------------------------------------
+
+typedef std::deque<chat_message> chat_message_queue;
+
+//----------------------------------------------------------------------
+
+class chat_participant
+{
+public:
+ virtual ~chat_participant() {}
+ virtual void deliver(const chat_message& msg) = 0;
+};
+
+typedef boost::shared_ptr<chat_participant> chat_participant_ptr;
+
+//----------------------------------------------------------------------
+
+class chat_room
+{
+public:
+ void join(chat_participant_ptr participant)
+ {
+ participants_.insert(participant);
+ std::for_each(recent_msgs_.begin(), recent_msgs_.end(),
+ boost::bind(&chat_participant::deliver, participant, _1));
+ }
+
+ void leave(chat_participant_ptr participant)
+ {
+ participants_.erase(participant);
+ }
+
+ void deliver(const chat_message& msg)
+ {
+ recent_msgs_.push_back(msg);
+ while (recent_msgs_.size() > max_recent_msgs)
+ recent_msgs_.pop_front();
+
+ std::for_each(participants_.begin(), participants_.end(),
+ boost::bind(&chat_participant::deliver, _1, boost::ref(msg)));
+ }
+
+private:
+ std::set<chat_participant_ptr> participants_;
+ enum { max_recent_msgs = 100 };
+ chat_message_queue recent_msgs_;
+};
+
+//----------------------------------------------------------------------
+
+class chat_session
+ : public chat_participant,
+ public boost::enable_shared_from_this<chat_session>
+{
+public:
+ chat_session(boost::asio::io_service& io_service, chat_room& room)
+ : socket_(io_service),
+ room_(room)
+ {
+ }
+
+ tcp::socket& socket()
+ {
+ return socket_;
+ }
+
+ void start()
+ {
+ room_.join(shared_from_this());
+ boost::asio::async_read(socket_,
+ boost::asio::buffer(read_msg_.data(), chat_message::header_length),
+ boost::bind(
+ &chat_session::handle_read_header, shared_from_this(),
+ boost::asio::placeholders::error));
+ }
+
+ void deliver(const chat_message& msg)
+ {
+ bool write_in_progress = !write_msgs_.empty();
+ write_msgs_.push_back(msg);
+ if (!write_in_progress)
+ {
+ boost::asio::async_write(socket_,
+ boost::asio::buffer(write_msgs_.front().data(),
+ write_msgs_.front().length()),
+ boost::bind(&chat_session::handle_write, shared_from_this(),
+ boost::asio::placeholders::error));
+ }
+ }
+
+ void handle_read_header(const boost::system::error_code& error)
+ {
+ if (!error && read_msg_.decode_header())
+ {
+ boost::asio::async_read(socket_,
+ boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
+ boost::bind(&chat_session::handle_read_body, shared_from_this(),
+ boost::asio::placeholders::error));
+ }
+ else
+ {
+ room_.leave(shared_from_this());
+ }
+ }
+
+ void handle_read_body(const boost::system::error_code& error)
+ {
+ if (!error)
+ {
+ room_.deliver(read_msg_);
+ boost::asio::async_read(socket_,
+ boost::asio::buffer(read_msg_.data(), chat_message::header_length),
+ boost::bind(&chat_session::handle_read_header, shared_from_this(),
+ boost::asio::placeholders::error));
+ }
+ else
+ {
+ room_.leave(shared_from_this());
+ }
+ }
+
+ void handle_write(const boost::system::error_code& error)
+ {
+ if (!error)
+ {
+ write_msgs_.pop_front();
+ if (!write_msgs_.empty())
+ {
+ boost::asio::async_write(socket_,
+ boost::asio::buffer(write_msgs_.front().data(),
+ write_msgs_.front().length()),
+ boost::bind(&chat_session::handle_write, shared_from_this(),
+ boost::asio::placeholders::error));
+ }
+ }
+ else
+ {
+ room_.leave(shared_from_this());
+ }
+ }
+
+private:
+ tcp::socket socket_;
+ chat_room& room_;
+ chat_message read_msg_;
+ chat_message_queue write_msgs_;
+};
+
+typedef boost::shared_ptr<chat_session> chat_session_ptr;
+
+//----------------------------------------------------------------------
+
+class chat_server
+{
+public:
+ chat_server(boost::asio::io_service& io_service,
+ const tcp::endpoint& endpoint)
+ : io_service_(io_service),
+ acceptor_(io_service, endpoint)
+ {
+ start_accept();
+ }
+
+ void start_accept()
+ {
+ chat_session_ptr new_session(new chat_session(io_service_, room_));
+ acceptor_.async_accept(new_session->socket(),
+ boost::bind(&chat_server::handle_accept, this, new_session,
+ boost::asio::placeholders::error));
+ }
+
+ void handle_accept(chat_session_ptr session,
+ const boost::system::error_code& error)
+ {
+ if (!error)
+ {
+ session->start();
+ }
+
+ start_accept();
+ }
+
+private:
+ boost::asio::io_service& io_service_;
+ tcp::acceptor acceptor_;
+ chat_room room_;
+};
+
+typedef boost::shared_ptr<chat_server> chat_server_ptr;
+typedef std::list<chat_server_ptr> chat_server_list;
+
+//----------------------------------------------------------------------
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc < 2)
+ {
+ std::cerr << "Usage: chat_server <port> [<port> ...]\n";
+ return 1;
+ }
+
+ boost::asio::io_service io_service;
+
+ chat_server_list servers;
+ for (int i = 1; i < argc; ++i)
+ {
+ using namespace std; // For atoi.
+ tcp::endpoint endpoint(tcp::v4(), atoi(argv[i]));
+ chat_server_ptr server(new chat_server(io_service, endpoint));
+ servers.push_back(server);
+ }
+
+ io_service.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
diff --git a/doc/html/boost_asio/example/cpp03/chat/posix_chat_client.cpp b/doc/html/boost_asio/example/cpp03/chat/posix_chat_client.cpp
new file mode 100644
index 0000000000..434f9f5916
--- /dev/null
+++ b/doc/html/boost_asio/example/cpp03/chat/posix_chat_client.cpp
@@ -0,0 +1,205 @@
+//
+// posix_chat_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 <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <boost/array.hpp>
+#include <boost/bind.hpp>
+#include <boost/asio.hpp>
+#include "chat_message.hpp"
+
+#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+
+using boost::asio::ip::tcp;
+namespace posix = boost::asio::posix;
+
+class posix_chat_client
+{
+public:
+ posix_chat_client(boost::asio::io_service& io_service,
+ tcp::resolver::iterator endpoint_iterator)
+ : socket_(io_service),
+ input_(io_service, ::dup(STDIN_FILENO)),
+ output_(io_service, ::dup(STDOUT_FILENO)),
+ input_buffer_(chat_message::max_body_length)
+ {
+ boost::asio::async_connect(socket_, endpoint_iterator,
+ boost::bind(&posix_chat_client::handle_connect, this,
+ boost::asio::placeholders::error));
+ }
+
+private:
+
+ void handle_connect(const boost::system::error_code& error)
+ {
+ if (!error)
+ {
+ // Read the fixed-length header of the next message from the server.
+ boost::asio::async_read(socket_,
+ boost::asio::buffer(read_msg_.data(), chat_message::header_length),
+ boost::bind(&posix_chat_client::handle_read_header, this,
+ boost::asio::placeholders::error));
+
+ // Read a line of input entered by the user.
+ boost::asio::async_read_until(input_, input_buffer_, '\n',
+ boost::bind(&posix_chat_client::handle_read_input, this,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred));
+ }
+ }
+
+ void handle_read_header(const boost::system::error_code& error)
+ {
+ if (!error && read_msg_.decode_header())
+ {
+ // Read the variable-length body of the message from the server.
+ boost::asio::async_read(socket_,
+ boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
+ boost::bind(&posix_chat_client::handle_read_body, this,
+ boost::asio::placeholders::error));
+ }
+ else
+ {
+ close();
+ }
+ }
+
+ void handle_read_body(const boost::system::error_code& error)
+ {
+ if (!error)
+ {
+ // Write out the message we just received, terminated by a newline.
+ static char eol[] = { '\n' };
+ boost::array<boost::asio::const_buffer, 2> buffers = {{
+ boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
+ boost::asio::buffer(eol) }};
+ boost::asio::async_write(output_, buffers,
+ boost::bind(&posix_chat_client::handle_write_output, this,
+ boost::asio::placeholders::error));
+ }
+ else
+ {
+ close();
+ }
+ }
+
+ void handle_write_output(const boost::system::error_code& error)
+ {
+ if (!error)
+ {
+ // Read the fixed-length header of the next message from the server.
+ boost::asio::async_read(socket_,
+ boost::asio::buffer(read_msg_.data(), chat_message::header_length),
+ boost::bind(&posix_chat_client::handle_read_header, this,
+ boost::asio::placeholders::error));
+ }
+ else
+ {
+ close();
+ }
+ }
+
+ void handle_read_input(const boost::system::error_code& error,
+ std::size_t length)
+ {
+ if (!error)
+ {
+ // Write the message (minus the newline) to the server.
+ write_msg_.body_length(length - 1);
+ input_buffer_.sgetn(write_msg_.body(), length - 1);
+ input_buffer_.consume(1); // Remove newline from input.
+ write_msg_.encode_header();
+ boost::asio::async_write(socket_,
+ boost::asio::buffer(write_msg_.data(), write_msg_.length()),
+ boost::bind(&posix_chat_client::handle_write, this,
+ boost::asio::placeholders::error));
+ }
+ else if (error == boost::asio::error::not_found)
+ {
+ // Didn't get a newline. Send whatever we have.
+ write_msg_.body_length(input_buffer_.size());
+ input_buffer_.sgetn(write_msg_.body(), input_buffer_.size());
+ write_msg_.encode_header();
+ boost::asio::async_write(socket_,
+ boost::asio::buffer(write_msg_.data(), write_msg_.length()),
+ boost::bind(&posix_chat_client::handle_write, this,
+ boost::asio::placeholders::error));
+ }
+ else
+ {
+ close();
+ }
+ }
+
+ void handle_write(const boost::system::error_code& error)
+ {
+ if (!error)
+ {
+ // Read a line of input entered by the user.
+ boost::asio::async_read_until(input_, input_buffer_, '\n',
+ boost::bind(&posix_chat_client::handle_read_input, this,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred));
+ }
+ else
+ {
+ close();
+ }
+ }
+
+ void close()
+ {
+ // Cancel all outstanding asynchronous operations.
+ socket_.close();
+ input_.close();
+ output_.close();
+ }
+
+private:
+ tcp::socket socket_;
+ posix::stream_descriptor input_;
+ posix::stream_descriptor output_;
+ chat_message read_msg_;
+ chat_message write_msg_;
+ boost::asio::streambuf input_buffer_;
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 3)
+ {
+ std::cerr << "Usage: posix_chat_client <host> <port>\n";
+ return 1;
+ }
+
+ boost::asio::io_service io_service;
+
+ tcp::resolver resolver(io_service);
+ tcp::resolver::query query(argv[1], argv[2]);
+ tcp::resolver::iterator iterator = resolver.resolve(query);
+
+ posix_chat_client c(io_service, iterator);
+
+ io_service.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << "\n";
+ }
+
+ return 0;
+}
+
+#else // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+int main() {}
+#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)