zoukankan      html  css  js  c++  java
  • boost::asio实现一个echo服务器

    以前使用ACE实现Server框架,但是觉得太笨重,决定采用boost.asio来写服务器程序: 
    1.服务器构建在linux上面;当然也可以在windows下运行 
    2.io部分采用非阻塞模式、业务逻辑部分采用同步线程池实现 
    3.封装io操作及状态,用户应用程序无需关心io详细操作

    所以决定采用boost::asio框架来写服务器:

    boost::asio::io_service提供了核心IO功能、和异步IO对象,它包括: 
    boost::asio::ip::tcp::socket 
    boost::asio::ip::tcp::acceptor 
    boost::asio::ip::udp::socket 
    boost::asio::deadline_timer 
    io_service支持线程安全、共享对象安全;调用run()函数未完成时会引发reset();

    boost.asio异步方式的函数前面都加有async_前缀,函数参数中会要求放入一个回调函数(或仿函数);异步操作执行完后无论有没有完成都会立即返回,这时候可以处理其他事情,等到回调函数被调用就说明异步操作已经完毕。 
    boost.asio的很多回调函数值接收boost::system::error_code参数,在实际使用中是不够的,所以一般的仿函数都会携带一堆数据作为回调,或使用boost::bind来绑定一堆数据。 
    只有boost.asio.run()运行后回调对象才会被调用,否则即使系统已经完成了异步操作也不会有任何动作!

    
    
    //下面是一个异步模式的简单的Tcp echo服务器
    #include <iostream>
    #include <string>
    #include <boost/asio.hpp>
    #include <boost/bind.hpp>
    #include <boost/smart_ptr.hpp>
    
    using namespace boost::asio;
    using boost::system::error_code;
    using ip::tcp;
    
    struct CHelloWorld_Service
    {
        //类的初始化创建:设置io_service, 设置1000端口
        CHelloWorld_Service(io_service &iosev)
             :m_iosev(iosev),m_acceptor(iosev, tcp::endpoint(tcp::v4(), 1000))
        {
        }
        
        //创建一个tcp的socket;且还是侦听
        void start()
        {
            // 开始等待连接(非阻塞)
             boost::shared_ptr<tcp::socket> psocket(new tcp::socket(m_iosev));
    
            // 触发的事件只有error_code参数,所以用boost::bind把socket绑定进去
             m_acceptor.async_accept(*psocket, boost::bind(&CHelloWorld_Service::accept_handler, this, psocket, _1) );
         }
    
        // 有客户端连接时accept_handler触发
        void accept_handler(boost::shared_ptr<tcp::socket> psocket, error_code ec)
         {
            if(ec) return;
    
            // 继续等待连接
             start();
    
            // 显示远程IP
             std::cout << psocket->remote_endpoint().address() << std::endl;
    
            // 发送信息(非阻塞)
             boost::shared_ptr<std::string> pstr(new std::string("hello async world!"));
             psocket->async_write_some(buffer(*pstr),
                 boost::bind(&CHelloWorld_Service::write_handler, this, pstr, _1, _2)
                 );
         }
    
        // 异步写操作完成后write_handler触发
        void write_handler(boost::shared_ptr<std::string> pstr, error_code ec, size_t bytes_transferred)
         {
            if(ec)
                 std::cout<< "发送失败!" << std::endl;
            else
                 std::cout<< *pstr << " 已发送" << std::endl;
         }
    
    private:
         io_service &m_iosev;
         ip::tcp::acceptor m_acceptor;
    };
    
    
    int main(int argc, char* argv[])
    {
         //建立io服务器
         io_service iosev;
    
         CHelloWorld_Service sev(iosev);
    
        //开始侦听socket的连接;和开始接收远程数据
         sev.start();
    
         //开始执行回调函数
         iosev.run();
    
        return 0;
    }

    例子分析: 
    1.调用sev.start()开始接受客户端连接。async_accept()其实就是注册了一个回调函数;所以它会立即返回。 
    2.iosev.run()方法是一个循环,负责分发异步回调函数,只有当所有的异步操作执行完后才会返回。 
    3.为了保证start()中的m_accptor.async_accept操作所用的socket在整个异步操作期间都是有效的,而且以后所有的客户端连接进来后该socket都是有效地,这里的解决办法是使用一个带计数的智能指针,shared_ptr,并将该指针绑定到回调函数上。该智能指针的生存周期等同于sev的生存周期。 
    4.一旦有客户端连接,回调函数accept_handler()就会执行,在该函数中首先调用start()继续异步等待其他客户端连接;然后使用start()绑定进来的socket进行接收远程客户端的连接 
    5.例子程序中发送数据也使用了异步模式async_write_some,同样需要保证整个异步发送期间缓冲区的有效性,所以使用了shared_ptr<string>参数 
    6.对于客户端connect, read_some前面也可加入async_前缀,按照异步方式执行;

  • 相关阅读:
    Server Tomcat v8.0 Server at localhost was unable to start within 45 seconds. If the server requires more time, try increasing the timeout in the server editor.
    用户画像——“打标签”
    python replace函数替换无效问题
    python向mysql插入数据一直报TypeError: must be real number,not str
    《亿级用户下的新浪微博平台架构》读后感
    【2-10】标准 2 维表问题
    【2-8】集合划分问题(给定要分成几个集合)
    【2-7】集合划分问题
    【2-6】排列的字典序问题
    【2-5】有重复元素的排列问题
  • 原文地址:https://www.cnblogs.com/liaocheng/p/4254679.html
Copyright © 2011-2022 走看看