首页 > 代码库 > Boost.Asio c++ 网络编程翻译(14)
Boost.Asio c++ 网络编程翻译(14)
using namespace boost::asio;
io_service service;
struct connection : boost::enable_shared_from_this<connection> {
typedef boost::system::error_code error_code;
typedef boost::shared_ptr<connection> ptr;
connection() : sock_(service), started_(true) {}
void start(ip::tcp::endpoint ep) {
sock_.async_connect(ep,
boost::bind(&connection::on_connect, shared_from_this(),
_1)); }
void stop() {
if ( !started_) return;
started_ = false;
sock_.close();
}
bool started() { return started_; }
private:
void on_connect(const error_code & err) {
// here you decide what to do with the connection: read or
write
if ( !err) do_read();
else stop();
}
void on_read(const error_code & err, size_t bytes) {
if ( !started() ) return;
std::string msg(read_buffer_, bytes);
if ( msg == "can_login")
else if ( msg.find("data ") == 0)
else if ( msg == "login_fail")
do_write("access_data");
process_data(msg);
stop();
}
void on_write(const error_code & err, size_t bytes) {
do_read(); }
void do_read() {
sock_.async_read_some(buffer(read_buffer_),
boost::bind(&connection::on_read, shared_from_this(),
_1, _2)); }
void do_write(const std::string & msg) {
if ( !started() ) return;
// note: in case you want to send several messages before
// doing another async_read, you‘ll need several write
buffers!
std::copy(msg.begin(), msg.end(), write_buffer_);
sock_.async_write_some(buffer(write_buffer_, msg.size()),
boost::bind(&connection::on_write, shared_from_this(),
_1, _2)); }
void process_data(const std::string & msg) {
// process what comes from server, and then perform another
write }
private:
ip::tcp::socket sock_;
enum { max_msg = 1024 };
char read_buffer_[max_msg];
char write_buffer_[max_msg];
bool started_;
};
int main(int argc, char* argv[]) {
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"),
8001);
connection::ptr(new connection)->start(ep);
}
在所有异步调用中,我们传递一个boost::bind仿函数当作参数。这个仿函数内部包含了一个智能指针,指向connection实例。只要有一个异步操作等待时,Boost.Asio会保存boost::bind仿函数的拷贝,这个拷贝保存了指向连接实例的一个智能指针,从而保证connection实例保持活动。问题解决!
当然,connection类仅仅是一个skeleton类;你需要根据你的需求对它进行调整(它看起来会和服务端的情况相当不同)。
你需要注意创建一个新的连接是相当简单的:connection::ptr(new connection)- >start(ep)。这个方法启动了到服务端的(异步)连接。当你需要关闭这个连接时,调用stop()。
当实例被启动时(start()),它将会等待被连接。当连接发生时。on_connect()被调用。如果没有错误发生,它启动一个read操作(do_read())。当read操作结束时,你解析这个消息;你应用的on_read()看起来会各种各样。当你写回一个消息时,你需要把它拷贝到缓冲区,然后像我在do_write()方法中所做的一样将其发送出去,因为再一次,这个缓冲区需要在这个异步写操作中一直存活。最后需要注意的一点——当写回时,你需要指定写入的数量,否则,整个缓冲区都会被发送出去。
总结
网络api实际上要大得多,这个章节只是一个参考,当你在实现你自己的网络应用时,你需要回来查看。
Boost.Asio实现了端点的概念,你可以认为是IP和端口。如果你不知道准确的IP,你可以使用resolver对象将主机名,例如www.yahoo.com转换为一个或多个IP地址。
我们也可以看到API的核心——socket类。Boost.Asio提供了TCP、UDP和 ICMP的实现。但是你可以用你自己的协议来对它进行扩展;当然,这个工作不适合胆小的人。
异步编程是必要之恶。你会明白为什么有时候需要它,尤其在写服务端的时候。调用service.run()来实现异步循环就已经可以让你很开心,但是有时候你需要更进一步,尝试使用run_one()、poll()或者poll_one()。
当实现异步时,你可以用你自己方法来异步执行;使用service.post()或者service.dispatch()。
最后,为了使socket和缓冲区(read或者write)在整个异步操作的生命周期中一直活动,我们需要采取特殊的防护措施。你的连接类需要继承自enabled_shared_from_this,在内部保存它需要的缓冲区,而且每个异步调用都要传递一个智能指针给this操作。
下一章会让你进行实战操作;在实现回显客户端/服务端应用时会有大量的上手编程。
Boost.Asio c++ 网络编程翻译(14)