Boost.Asio C++ Chapter_2

/*同步客户端例子*/
using boost::asio;
//创建io_service实例
io_service service; 
//创建连接的地址和端口
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 2001);
//把socket连接到你创建的地址和端口
ip::tcp::socket sock(service);
sock.connect(ep);



/*下面是一个简单的使用Boost.Asio的服务端:*/
typedef boost::shared_ptr<ip::tcp::socket> socket_ptr;
//创建io_service实例
io_service service;
ip::tcp::endpoint ep( ip::tcp::v4(), 2001); // listen on 2001
//创建一个接收器,用来接收客户端连接的对象
ip::tcp::acceptor acc(service, ep);
//循环中创建一个虚拟的socket等待客户端的连接
while ( true) {
    socket_ptr sock(new ip::tcp::socket(service));
    acc.accept(*sock);
    boost::thread( boost::bind(client_session, sock));
}
//当连接时,创建线程来处理
void client_session(socket_ptr sock) {
    while ( true) {
        char data[512];
        size_t len = sock->read_some(buffer(data));
        if ( len > 0)
            write(*sock, buffer("ok", 2));
    }
}



/*创建一个异步的客户端*/
using boost::asio;
//创建io_service实例
io_service service;
//指定连接的地址以及创建socket
ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"), 2001);
ip::tcp::socket sock(service);
//当连接完成时(其完成处理程序)就异步地连接到了指定的地址和端口,也就是说,connect_handler被调用了
sock.async_connect(ep, connect_handler);
service.run();
//当connect_handler被调用时,检查错误代码(ec),如果成功,你就可以向服务端进行异步的写入
void connect_handler(const boost::system::error_code & ec) {
    // 如果ec返回成功我们就可以知道连接成功了
}
//注意:只要还有待处理的异步操作,servece.run()循环就会一直运行。
//在上述例子中,只执行了一个这样的操作,就是socket的async_connect。在这之后,service.run()就退出了。



/*下面的代码是一个基本的异步服务端*/
using boost::asio;
typedef boost::shared_ptr<ip::tcp::socket> socket_ptr;
//创建io_service实例
io_service service;
//指定监听的端口
ip::tcp::endpoint ep( ip::tcp::v4(), 2001); // 监听端口2001
//创建接收器acc,一个接受客户端连接
ip::tcp::acceptor acc(service, ep);
//创建虚拟的socket,异步等待客户端连接的对象
socket_ptr sock(new ip::tcp::socket(service));
start_accept(sock);
//运行异步service.run()循环
service.run();
void start_accept(socket_ptr sock) {
    acc.async_accept(*sock, boost::bind( handle_accept, sock, _1) );
}
//当接收到客户端连接时,handle_accept被调用(调用async_accept的完成处理程序)。
//如果没有错误,这个socket就可以用来做读写操作
void handle_accept(socket_ptr sock, const boost::system::error_code &err) {
    if ( err) return;
    // 从这里开始, 你可以从socket读取或者写入
    socket_ptr sock(new ip::tcp::socket(service));
    start_accept(sock);
}
//在使用这个socket之后,你创建了一个新的socket,然后再次调用start_accept(),
//用来创建另外一个“等待客户端连接”的异步操作,从而使service.run()循环一直保持忙碌状态。


/*有一个io_service实例和一个处理线程的单线程例子*/
io_service service; // 所有socket操作都由service来处理 
ip::tcp::socket sock1(service); // all the socket operations are handled by service 
ip::tcp::socket sock2(service); 
sock1.async_connect( ep, connect_handler); 
sock2.async_connect( ep, connect_handler); 
deadline_timer t(service, boost::posixtime::seconds(5));
t.async_wait(timeout_handler); 
service.run();



/*有一个io_service实例和多个处理线程的多线程例子*/
io_service service;
ip::tcp::socket sock1(service);
ip::tcp::socket sock2(service);
sock1.async_connect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service, boost::posixtime::seconds(5));
t.async_wait(timeout_handler);
for ( int i = 0; i < 5; ++i)
    boost::thread( run_service);
void run_service()
{
    service.run();
}


/*有多个io_service实例和多个处理线程的多线程例子*/
io_service service[2];
ip::tcp::socket sock1(service[0]);
ip::tcp::socket sock2(service[1]);
sock1.async_connect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service[0], boost::posixtime::seconds(5));
t.async_wait(timeout_handler);
for ( int i = 0; i < 2; ++i)
    boost::thread( boost::bind(run_service, i));
void run_service(int idx)
{
    service[idx].run();
}


/*
第一种情况是非常基础的应用程序。因为是串行的方式,所以当几个处理程序需要被同时调用时,你通常会遇到瓶颈。
如果一个处理程序需要花费很长的时间来执行,所有随后的处理程序都不得不等待。

第二种情况是比较适用的应用程序。他是非常强壮的——如果几个处理程序被同时调用了(这是有可能的),它们会在各自的线程里面被调用。
唯一的瓶颈就是所有的处理线程都很忙的同时又有新的处理程序被调用。然而,这是有快速的解决方式的,增加处理线程的数目即可。

第三种情况是最复杂和最难理解的。你只有在第二种情况不能满足需求时才使用它。这种情况一般就是当你有成千上万实时(socket)连接时。
你可以认为每一个处理线程(运行io_service::run()的线程)有它自己的select/epoll循环;它等待任意一个socket连接,然后等待一个读写操作,
当它发现这种操作时,就执行。大部分情况下,你不需要担心什么,唯一你需要担心的就是当你监控的socket数目以指数级的方式增长时(超过1000个的socket)。
在那种情况下,有多个select/epoll循环会增加应用的响应时间。
*/


/*
当使用socket缓冲区的时候,你会有一个buffer实例在异步调用时一直存在(使用boost::shared_array<>)。在这里,我们可以使用同样的方式,
通过创建一个类并在其内部管理socket和它的读写缓冲区。然后,对于所有的异步操作,传递一个包含智能指针的boost::bind仿函数给它:
*/

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) {
        // 这里你决定用这个连接做什么: 读取或者写入
        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") do_write("access_data");
        else if ( msg.find("data ") == 0) process_data(msg);
        else if ( msg == "login_fail") 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;
        // 注意: 因为在做另外一个async_read操作之前你想要发送多个消息, 
        // 所以你需要多个写入buffer
        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) {
        // 处理服务端来的内容,然后启动另外一个写入操作
    }
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类仅仅是一个框架类;你需要根据你的需求对它进行调整(它看起来会和当前服务端例子的情况相当不同)。

你需要注意的是创建一个新的连接是相当简单的:connection::ptr(new connection)- >start(ep)。这个方法启动了到服务端的(异步)连接。
当你需要关闭这个连接时,调用stop()。

当实例被启动时(start()),它会等待客户端的连接。当连接发生时。on_connect()被调用。如果没有错误发生,它启动一个read操作(do_read())。
当read操作结束时,你就可以解析这个消息;当然你应用的on_read()看起来会各种各样。
而当你写回一个消息时,你需要把它拷贝到缓冲区,然后像我在do_write()方法中所做的一样将其发送出去,因为这个缓冲区同样需要在这个异步写操作中一直存活。
最后需要注意的一点——当写回时,你需要指定写入的数量,否则,整个缓冲区都会被发送出去。
*/
原文链接:https://mmoaay.gitbooks.io/boost-asio-cpp-network-programming-chinese/content/Chapter2.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值