Add a new POSIX-specific chat client showing how to use the
posix::stream_descriptor class.
This commit is contained in:
parent
5d79ded555
commit
d48c916ff0
@ -114,6 +114,7 @@ noinst_PROGRAMS = \
|
||||
|
||||
if !WINDOWS_TARGET
|
||||
noinst_PROGRAMS += \
|
||||
examples/chat/posix_chat_client \
|
||||
examples/local/connect_pair \
|
||||
examples/local/iostream_client \
|
||||
examples/local/stream_server \
|
||||
@ -386,6 +387,7 @@ examples_tutorial_daytime6_server_SOURCES = examples/tutorial/daytime6/server.cp
|
||||
examples_tutorial_daytime7_server_SOURCES = examples/tutorial/daytime7/server.cpp
|
||||
|
||||
if !WINDOWS_TARGET
|
||||
examples_chat_posix_chat_client_SOURCES = examples/chat/posix_chat_client.cpp
|
||||
examples_local_connect_pair_SOURCES = examples/local/connect_pair.cpp
|
||||
examples_local_iostream_client_SOURCES = examples/local/iostream_client.cpp
|
||||
examples_local_stream_server_SOURCES = examples/local/stream_server.cpp
|
||||
|
@ -33,6 +33,12 @@ protocol with a fixed length message header and variable length message body.
|
||||
* [@../src/examples/chat/chat_client.cpp]
|
||||
* [@../src/examples/chat/chat_server.cpp]
|
||||
|
||||
The following POSIX-specific chat client demonstrates how to use the
|
||||
[link asio.reference.posix.stream_descriptor posix::stream_descriptor] class to
|
||||
perform console input and output.
|
||||
|
||||
* [@../src/examples/chat/posix_chat_client.cpp]
|
||||
|
||||
|
||||
[heading Echo]
|
||||
|
||||
|
@ -92,7 +92,8 @@ asio.reference.async_read_until async_read_until()] free functions.
|
||||
|
||||
[link asio.reference.posix__stream_descriptor posix::stream_descriptor],
|
||||
[link asio.reference.posix__basic_stream_descriptor posix::basic_stream_descriptor],
|
||||
[link asio.reference.posix__stream_descriptor_service posix::stream_descriptor_service].
|
||||
[link asio.reference.posix__stream_descriptor_service posix::stream_descriptor_service],
|
||||
[link asio.examples.chat Chat example].
|
||||
|
||||
[heading Notes]
|
||||
|
||||
|
216
asio/src/examples/chat/posix_chat_client.cpp
Normal file
216
asio/src/examples/chat/posix_chat_client.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
//
|
||||
// posix_chat_client.cpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2008 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 <boost/array.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include "asio.hpp"
|
||||
#include "chat_message.hpp"
|
||||
|
||||
#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
|
||||
|
||||
using asio::ip::tcp;
|
||||
namespace posix = asio::posix;
|
||||
|
||||
class posix_chat_client
|
||||
{
|
||||
public:
|
||||
posix_chat_client(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)
|
||||
{
|
||||
// Try connecting to the first endpoint.
|
||||
tcp::endpoint endpoint = *endpoint_iterator;
|
||||
socket_.async_connect(endpoint,
|
||||
boost::bind(&posix_chat_client::handle_connect, this,
|
||||
asio::placeholders::error, ++endpoint_iterator));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void handle_connect(const asio::error_code& error,
|
||||
tcp::resolver::iterator endpoint_iterator)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
// Read the fixed-length header of the next message from the server.
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(read_msg_.data(), chat_message::header_length),
|
||||
boost::bind(&posix_chat_client::handle_read_header, this,
|
||||
asio::placeholders::error));
|
||||
|
||||
// Read a line of input entered by the user.
|
||||
asio::async_read_until(input_, input_buffer_, '\n',
|
||||
boost::bind(&posix_chat_client::handle_read_input, this,
|
||||
asio::placeholders::error,
|
||||
asio::placeholders::bytes_transferred));
|
||||
}
|
||||
else if (endpoint_iterator != tcp::resolver::iterator())
|
||||
{
|
||||
// That endpoint didn't work, try the next one.
|
||||
socket_.close();
|
||||
tcp::endpoint endpoint = *endpoint_iterator;
|
||||
socket_.async_connect(endpoint,
|
||||
boost::bind(&posix_chat_client::handle_connect, this,
|
||||
asio::placeholders::error, ++endpoint_iterator));
|
||||
}
|
||||
}
|
||||
|
||||
void handle_read_header(const asio::error_code& error)
|
||||
{
|
||||
if (!error && read_msg_.decode_header())
|
||||
{
|
||||
// Read the variable-length body of the message from the server.
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(read_msg_.body(), read_msg_.body_length()),
|
||||
boost::bind(&posix_chat_client::handle_read_body, this,
|
||||
asio::placeholders::error));
|
||||
}
|
||||
else
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void handle_read_body(const asio::error_code& error)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
// Write out the message we just received, terminated by a newline.
|
||||
static char eol[] = { '\n' };
|
||||
boost::array<asio::const_buffer, 2> buffers = {{
|
||||
asio::buffer(read_msg_.body(), read_msg_.body_length()),
|
||||
asio::buffer(eol) }};
|
||||
asio::async_write(output_, buffers,
|
||||
boost::bind(&posix_chat_client::handle_write_output, this,
|
||||
asio::placeholders::error));
|
||||
}
|
||||
else
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void handle_write_output(const asio::error_code& error)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
// Read the fixed-length header of the next message from the server.
|
||||
asio::async_read(socket_,
|
||||
asio::buffer(read_msg_.data(), chat_message::header_length),
|
||||
boost::bind(&posix_chat_client::handle_read_header, this,
|
||||
asio::placeholders::error));
|
||||
}
|
||||
else
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void handle_read_input(const asio::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();
|
||||
asio::async_write(socket_,
|
||||
asio::buffer(write_msg_.data(), write_msg_.length()),
|
||||
boost::bind(&posix_chat_client::handle_write, this,
|
||||
asio::placeholders::error));
|
||||
}
|
||||
else if (error == 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();
|
||||
asio::async_write(socket_,
|
||||
asio::buffer(write_msg_.data(), write_msg_.length()),
|
||||
boost::bind(&posix_chat_client::handle_write, this,
|
||||
asio::placeholders::error));
|
||||
}
|
||||
else
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void handle_write(const asio::error_code& error)
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
// Read a line of input entered by the user.
|
||||
asio::async_read_until(input_, input_buffer_, '\n',
|
||||
boost::bind(&posix_chat_client::handle_read_input, this,
|
||||
asio::placeholders::error,
|
||||
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_;
|
||||
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;
|
||||
}
|
||||
|
||||
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(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
|
||||
int main() {}
|
||||
#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
|
Loading…
Reference in New Issue
Block a user