Boost.Asio使用入门

  1、概述:Boost.Asio是一个跨平台的C++库,用于网络和底层I/O编程,可以在I/O对象(如socket)上执行同步和异步操作。

  2、简略的过程分析。以socket的连接操作为例:

  你的程序中需要至少定义一个io_service对象:boost::asio::io_service io_service。io_service表示程序到操作系统I/O服务的“连接”。

  为执行I/O操作,还需要一个I/O对象(通常需要使用io_service构造),如一个TCP套接字:boost::asio::ip::tcp::socket socket(io_service)。

  1)同步的连接过程中,发生以下事件序列(对应下面的左图):

  (1)程序通过I/O对象启动连接操作:socket.connect(server_endpoint);

  (2)I/O对象将请求转发给io_service;

  (3)io_service请求操作系统去执行连接操作;

  (4)操作系统将操作结果返回给io_service;

  (5)io_service将操作的(错误)结果转换成boost::system::error_code对象,并回传给I/O对象;

  (6)如果操作失败,I/O对象抛出boost::system::system_error异常。

  如果是使用以下方式,则只设置错误码,不会抛出异常:

boost::system::error_code ec;
socket.connect(server_endpoint, ec);

  2)异步的连接过程中,发生以下事件序列(对应下面的中图和右图):

  (1)程序通过I/O对象启动连接操作:socket.async_connect(server_endpoint, your_completion_handler);

  your_completion_handler是一个函数(对象),原型:void your_completion_handler(const boost::system::error_code& ec);

  (2)I/O对象将请求转发给io_service;

  (3)io_service发信号给操作系统,告知它去开始一个异步的连接操作;

  一段时间过去... ...注意,在同步的情形下,程序会一直等待连接操作完成,而异步则是先立即返回。

  (4)连接操作完成时,操作系统把结果放在队列中

  (5)程序必须调用io_service::run()(或类似函数)以取得操作结果。一般在你刚启动第一个异步操作时就要调用run();

  io_service对象未停止(stopped()返回false)且还有未完成的操作时,run()会一直阻塞,否则直接返回。

  asio保证了回调函数只会被run()所在线程调用。因此,若没有run(),回调函数永远不会被调用。

  (6)在run()中io_service将操作结果取出队列并翻译成error_code,然后传递给your_completion_handler

  Boost.Asio使用入门_第1张图片

  3、例子:

// g++ server.cpp -std=c++11 -lboost_system
// 一个简单的回显服务器

#include <array>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <type_traits>
#include <utility>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

// Class to manage the memory to be used for handler-based custom allocation.
// It contains a single block of memory which may be returned for allocation
// requests. If the memory is in use when an allocation request is made, the
// allocator delegates allocation to the global heap.
class handler_allocator
{
public:
    handler_allocator() : in_use_(false) {}
    
    handler_allocator(const handler_allocator&) = delete;
    handler_allocator& operator=(const handler_allocator&) = delete;
    
    void* allocate(std::size_t size)
    {
        if (!in_use_ && size < sizeof(storage_))
        {
            in_use_ = true;
            return &storage_;
        }
        else
            return ::operator new(size);
    }
    
    void deallocate(void* pointer)
    {
        if (pointer == &storage_)
            in_use_ = false;
        else
            ::operator delete(pointer);
    }

private:
    // Storage space used for handler-based custom memory allocation.
    typename std::aligned_storage<1024>::type storage_;
    
    // Whether the handler-based custom allocation storage has been used.
    bool in_use_;
};

// Wrapper class template for handler objects to allow handler memory
// allocation to be customised. Calls to operator() are forwarded to the
// encapsulated handler.
template <typename Handler>
class custom_alloc_handler
{
public:
    custom_alloc_handler(handler_allocator& a, Handler h) : allocator_(a), handler_(h) {}
    
    template <typename ...Args>
    void operator()(Args&&... args)
    {
        handler_(std::forward<Args>(args)...);
    }
    
    friend void* asio_handler_allocate(std::size_t size,
        custom_alloc_handler<Handler>* this_handler)
    {
        return this_handler->allocator_.allocate(size);
    }
    
    friend void asio_handler_deallocate(void* pointer, std::size_t /*size*/,
        custom_alloc_handler<Handler>* this_handler)
    {
        this_handler->allocator_.deallocate(pointer);
    }

private:
    handler_allocator& allocator_;
    Handler handler_;
};

// Helper function to wrap a handler object to add custom allocation.
template <typename Handler>
inline custom_alloc_handler<Handler> make_custom_alloc_handler(
    handler_allocator& a, Handler h)
{
    return custom_alloc_handler<Handler>(a, h);
}

class session : public std::enable_shared_from_this<session>
{
public:
    session(tcp::socket socket) : socket_(std::move(socket)) {}
    
    void start()
    {
        do_read();
    }

private:
    void do_read()
    {
        auto self(shared_from_this());
        socket_.async_read_some(boost::asio::buffer(data_),  // 异步read
            make_custom_alloc_handler(allocator_,
                [this, self](boost::system::error_code ec, std::size_t length)  // 读操作完成时调用。参数:操作结果、读取的字节数
                {
                    if (!ec)
                    {
                        do_write(length);
                    }
                }));
    }

    void do_write(std::size_t length)
    {
        auto self(shared_from_this());
        boost::asio::async_write(socket_, boost::asio::buffer(data_, length),  // 异步write
            make_custom_alloc_handler(allocator_,
                [this, self](boost::system::error_code ec, std::size_t /*length*/)
                {
                    if (!ec)
                    {
                        do_read();
                    }
                }));
    }
        
    tcp::socket socket_; // 和客户端通信的socket
    std::array<char, 1024> data_; // 保存从客户端接收到的数据
    
    // The allocator to use for handler-based custom memory allocation.
    handler_allocator allocator_;
};

class server
{
public:
    server(boost::asio::io_service& io_service, short port)
        : acceptor_(io_service, tcp::endpoint(tcp::v4(), port)), socket_(io_service)
    {
        do_accept();
    }

private:
    void do_accept()
    {
        acceptor_.async_accept(socket_,    // 异步accept,等待客户端连接
            [this](boost::system::error_code ec)    // 注册回调函数
            {
                if (!ec)
                    std::make_shared<session>(std::move(socket_))->start();

                do_accept();
            });
    }

    tcp::acceptor acceptor_;
    tcp::socket socket_;
};

int main(int argc, char* argv[])
{
    try
    {
        if (argc != 2)
        {
            std::cerr << "Usage: server <port>\n";
            return 1;
        }
        
        boost::asio::io_service io_service;
        server s(io_service, std::atoi(argv[1]));
        io_service.run();
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }
    
    return 0;
}

 

 

  参考资料:

  http://www.boost.org/

 

 

不断学习中。。。

你可能感兴趣的:(Boost.Asio使用入门)