• 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_前缀,按照异步方式执行;

  • 相关阅读:
    pytorch-第一章基本操作-基本使用方法 (1.torch.empty, 2.torch.rand, 3.torch.zeros, 4.torch.tensor, 5.x.new_ones,6.torch.rand_like, 7.torch.randn, 8.torch.from_numpy, 9.x.view(改变维度))
    mysql学习入门-数据库中库,表和内容操作
    校园客户端(DR)启动后提示我们缺失packet.dll,无法正常启动(7)
    DR客户端一直连接服务器....(6)
    优盘提示插入多卷集的最后一卷解决办法(5)
    apt-get默认下载路径
    Qt嵌入式开发环境搭建
    Ubuntu重启关机命令使用
    Linux如何修改网络环境参数
    VMware内部错误解决办法
  • 原文地址:https://www.cnblogs.com/liaocheng/p/4254679.html
Copyright © 2020-2023  润新知