zoukankan      html  css  js  c++  java
  • 【转】Asio与shared_ptr的一些注意事项

    经过一段时间的Asio使用,理清楚了一些基本的概念,这里和shared_ptr指针一起总结一下
    1、Asio中,不管写(Write)还是读(Read)都需要等待相应的事件完成后再发起下一次写或者读。读操作比较好办,在handle_read事件中直接进行下一次async_read操作就可以,但是写的话得自己管理一个deque队例,在写入操作完成后则自动把最顶的数据包弹出,然后开始写下一个(如果在缓冲队列中还有剩余的数据包);
    2、Asio中,不管任何的函数调用,若有未涉及error_code和涉及error_code的相同功能函数存在,则使用涉及error_code的函数调用,并且处理错误信息,否则io_service会因为异常而退出消息循环;
    3、若session或其它的类是使用shared_ptr来包装的,则需要将该类继承于enable_shared_from_this,否则会有可能在该对象已经被删除的情况下,该对象内的异步回调函数被调用,这样会导致程序崩溃退出;
    4、要注意,当类继承了enable_shared_from_this后,在构造函数中千万不要调用shared_from_this()函数,否则程序会抛掷异常;
    5、如果类中有方法暴露在外,而有可能是非线程安全调用的,则使用io_service::post函数来调用asio中的函数,以保证asio的回调是线程安全的;

    示例代码如下:(注:因为只是代码片断,随便手写,而且只是为了说明问题,所以并未检查过编译是否通过)

    #include <deque> 

    #include <boost/asio.hpp>

    #include <boost/shared_ptr.hpp>
    #include <boost/bind.hpp>
    #include <boost/enable_shared_from_this.hpp>
     
    using namespace boost::asio;
    using namespace boost::asio::ip;
     
    typedef boost::shared_ptr<tcp::socket> socket_ptr;
    typedef std::pair<void*, std::size_t> buffer_type;
    typedef std::deque<buffer_type> buffer_deque;
     
    class session : public boost::enable_shared_ptr_from_this<session>
    {
    public:
      session(io_service& ios, socket_ptr sp)
        : ios_(ios)
        , sp_(sp)
      {
      }
      void start_read()
      {
        async_read_until(*sp_, sb_, '\n', boost::bind(&session::handle_read, shared_from_this(), placeholders::error);
      }
      void send(void const* p, std::size_t size)
      {
        bool need_write = buffers_.empty();
        buffers_.push_back(std::make_pair(p, size));
        if (need_write) ios_.post(boost::bind(&session::do_send, shared_from_this()));
      }
      void close()
      {
        boost::system::error_code ec;
        sp_->shutdown(tcp::socket::shutdown_both, ec);
        if (ec) std::cout << ec.message().c_str() << std::endl;
        sp_->close(ec);
        if (ec) std::cout << ec.message().c_str() << std::endl;
      }
    private// do functions
      void do_send()
      {
        async_write(*sp, buffer(buffers_.begin()->first, buffers_.begin()->second), boost::bind(&sessions::handle_write, shared_from_this(), placeholders::error));
      }
    private// handlers
      void handle_read(boost::system::error_code const& ec)
      {
        if (!ec)
        {
          std::istream is(&sb_);
          std::string cmd;
          std::getline(is, cmd);
          // todo: handle command
          start_read(); // start next round
        }
        else
        {
          std::cout << ec.message().c_str() << std::endl;
          close();
        }
      }
      void handle_write(boost::system::error_code const& ec)
      {
        if (!ec)
        {
          buffers_.pop_front();
          if (!buffers_.empty()) do_send();
        }
        else
        {
          std::cout << ec.messages().c_str() << std::endl;
          close();
        }
      }
    private:
      io_service& ios_;
      socket_ptr sp_;
      streambuf sb_;
      buffer_deque buffers_;
    };

  • 相关阅读:
    Linux 下配置多路径及SCSI扫描磁盘重新发现大小
    vSphere vSwitch网络属性配置详解
    勤动脑筋
    如何用visual studio2013编写简单C语言程序
    两个字符窜,在母窜中查找子窜的位置
    如何安装Microsoft Visual C++6.0
    看张子阳如何在30岁前年薪超过30万觉得很有道理几点
    标志位放错了位置
    注意细节
    探索式学习
  • 原文地址:https://www.cnblogs.com/toosuo/p/2516874.html
Copyright © 2011-2022 走看看