ASIO的简单的通信的例子:
服务器端测试可用代码:
#include <ctime>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
std::string make_daytime_string()
{
using
namespace std; // For time_t, time and ctime;
time_t now = time(0);
return
ctime(&now);
}
class tcp_connection
: public boost::enable_shared_from_this<tcp_connection>
{
public:
typedef
boost::shared_ptr<tcp_connection> pointer;
static
pointer create(boost::asio::io_service& io_service)
{
return pointer(new tcp_connection(io_service));
}
tcp::socket& socket()
{
return socket_;
}
void
start()
{
message_ = make_daytime_string();
boost::asio::async_write(socket_, boost::asio::buffer(message_),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
private:
tcp_connection(boost::asio::io_service& io_service)
: socket_(io_service)
{
}
void
handle_write(const boost::system::error_code& /*error*/,
size_t /*bytes_transferred*/)
{
}
tcp::socket socket_;
std::string message_;
};
class tcp_server
{
public:
tcp_server(boost::asio::io_service& io_service)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), 13))
{
start_accept();
}
private:
void
start_accept()
{
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.io_service());
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
}
void
handle_accept(tcp_connection::pointer new_connection,
const boost::system::error_code& error)
{
if (!error)
{
new_connection->start();
start_accept();
}
}
tcp::acceptor acceptor_;
};
int main()
{
try
{
boost::asio::io_service io_service;
tcp_server server(io_service);
io_service.run();
}
catch
(std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return
0;
}
客户端测试可用代码:
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
int main(int argc, char* argv[])
{
try
{
boost::asio::io_service io_service;
tcp::resolver::query query("127.0.0.1", "13");
tcp::resolver resolver(io_service);
/*
tcp::resolver::iterator
endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator
end;
*/
tcp::socket socket(io_service);
boost::system::error_code error = boost::asio::error::host_not_found;
/*
while
(error && endpoint_iterator != end)
{
socket.close();
socket.connect(*endpoint_iterator++,
error);
}
*/
tcp::resolver::iterator iter = resolver.resolve(query);
socket.connect( *iter,error);
if
(error)
throw
boost::system::system_error(error);
for
(;;)
{
boost::array<char,
128> buf;
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(buf), error);
if
(error == boost::asio::error::eof)
break;
// Connection closed cleanly by peer.
else
if (error)
throw
boost::system::system_error(error); // Some other error.
std::cout.write(buf.data(), len);
}
}
catch
(std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return
0;
}
Asio
的聊天室的小例子:
chat_message.hpp
#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 length)
{
body_length_ = 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", body_length_);
memcpy(data_, header, header_length);
}
private:
char
data_[header_length + max_body_length];
size_t body_length_;
};
#endif // CHAT_MESSAGE_HPP
Server.cpp
#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"
//整个程序是一个tcp程序
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;
//----------------------------------------------------------------------
//聊天室很像QQ里面的组,或者说QQ里面的组就是一种聊天室,
//我们相信聊天室会有许多种,那种两个人私聊的地方也是一种聊天室
//这里面没有实现私聊
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_;
};
//----------------------------------------------------------------------
//程序不认识人,它只认识一个一个连接,所以一个连接就代表着一个人
//在聊天室环境下,一个session就是一个成员的加入
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());
//async_read是事件处理一个机制,使用回调函数从而实现事件处理器方法
//本示例大量采用这个机制,也就是异步机制
//通过回调函数可以形成一个事件链,即在回调函数中设置一个新的事件与新回调函数
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;
//----------------------------------------------------------------------
//它只做一件事,就是等待客户端连接;当客户端连接时,新建一个session
//然后把实际操作事务交给这个session,接着继续等待客户端连接。
class chat_server
{
public:
chat_server(boost::asio::io_service& io_service,
const tcp::endpoint& endpoint)
: io_service_(io_service),
acceptor_(io_service, endpoint)
{
//创建一个新的session,让它接受新的连接
chat_session_ptr new_session(new chat_session(io_service_, room_));
//接受新的连接,在socket上。
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();
std::cerr <<"lgb" <<std::endl;
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));
}
}
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;
}
客户端代码:
#include
<cstdlib>
#include <cstring>
#include <iostream>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include "chat_message.hpp"
//从这里可以看出来,对posix的支持是可选地编译在asio中的
//asio其时是一个纯头文件的库,它没有编译的概念,但是要实现asio的一些功能需要额外的条件
//所以这个测试有时必要的,这是做可移植一种努力
#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)
{
//
Try connecting to the first endpoint.
tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,
boost::bind(&posix_chat_client::handle_connect, this,
boost::asio::placeholders::error, ++endpoint_iterator));
}
private:
void handle_connect(const boost::system::error_code& error,
tcp::resolver::iterator endpoint_iterator)
{
if (!error)
{
//
Read the fixed-length header of the next message from the server.
//async_xxx一族函数实际上都上范型的,它们会从各种设计好的可读或可写对象中
//执行相应的操作,而不管这些操作实际上是什么
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));
}
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,
boost::asio::placeholders::error, ++endpoint_iterator));
}
}
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中的文件描述符的对等物
//asio认为POSIX中的用一个short整数来作为文件描述符是单调而不安全的
posix::stream_descriptor input_;
posix::stream_descriptor output_;
chat_message read_msg_;
chat_message write_msg_;
//这是一个来自std::streambuf的类型,它是对streambuf的一个定制
//STL的可扩展功能允许我们去这么做
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)