zoukankan      html  css  js  c++  java
  • win32下boost::asio进一步封装

    在网络通信中,我个人比较喜欢异步的方式。这样我程序就不会因为I/O的读写而导致线程阻塞。理想的工作方式是通知窗口的事件通知。windows中socket的底层其实是支持窗口事件通知的,但由于boost库比较强大,我就基于asio的库来实现这样的机制。

    由于是异步方式,当事件处理完成后,我希望将结果传递给回调函数,因此类中有下面3个函数:

        virtual void handler_connect(const boost::system::error_code& error);
        virtual void handler_send(const boost::system::error_code& error);
        virtual void handler_receive(const boost::system::error_code& error);

    参数传递过来的只是是否有错误。

    在主线程中,我只需要调用

    void connect();
    
    template<typename ConstBufferSequence>
    void send(const ConstBufferSequence& buffers);
    
    template<typename MutableBufferSequence>
    void receive(const MutableBufferSequence& buffers)

    这三个函数即可,处理完成后会自动调用上面的回调函数,使用回调函数来处理结果。

    asio中io_service的run会一直阻塞线程,所以需要将run在辅助线程中运行,但这样的话,回调函数就会在辅助线程中执行,为了保证线程安全性和消除MFC中不同线程执行后的代码异常,我需要将回调函数转入main线程中执行,这就应用了SendMessage函数了通知主线程窗口,下面详细的代码:

    #define WM_ASIO_MESSAGE (WM_USER + 1)
    
    using boost::asio::ip::tcp;
    using boost::asio::deadline_timer;
    
    template <typename CWinWnd>
    class Win32TcpClient
    {
        typedef Win32TcpClient<CWinWnd> MyClassName;
        typedef void (MyClassName::*handler_ptr)(const boost::system::error_code&);
    public:
        Win32TcpClient(boost::asio::io_service& ios,tcp::endpoint endpoint,CWinWnd* pWinWnd)
            :io_service_(ios),win_wnd_(pWinWnd),socket_(ios),
            endpoint_(endpoint),deadline_(ios),stop_(false),connect_timeout_(TIME_INF),handler_ptr_(NULL)
        {
            set_timeout(connect_timeout_);
        }
    
        enum {TIME_INF = -1};
        void connect()
        {
            deadline_.async_wait(boost::bind(&MyClassName::check_deadline, this));
            socket_.async_connect(endpoint_,
                boost::bind(&MyClassName::run_main_thread_handler,this,&MyClassName::handler_connect,
                boost::asio::placeholders::error));
        }
        void set_timeout(int timeout_seconds)
        {
            if (timeout_seconds == TIME_INF)
                deadline_.expires_at(boost::posix_time::pos_infin);
            else
                deadline_.expires_from_now(boost::posix_time::seconds(timeout_seconds));
        }
    
        void close()
        {
            stop_ = true;
            socket_.close();
        }
        
        template<typename ConstBufferSequence>
        void send(const ConstBufferSequence& buffers)
        {
    
            boost::asio::async_write(socket_,buffers,
                boost::bind(&MyClassName::run_main_thread_handler,this,&MyClassName::handler_send,
                boost::asio::placeholders::error));
        }
    
        template<typename MutableBufferSequence>
        void receive(const MutableBufferSequence& buffers)
        {
            boost::asio::async_read(socket_,buffers,
                boost::bind(&MyClassName::run_main_thread_handler, this,&MyClassName::handler_receive,
                boost::asio::placeholders::error));
    
        }
    
        void win_proc()
        {
            if(handler_ptr_ != NULL)
                (this->*handler_ptr_)(error_code_);
        }
        virtual void handler_connect(const boost::system::error_code& error){}
        virtual void handler_send(const boost::system::error_code& error){}
        virtual void handler_receive(const boost::system::error_code& error){}
    private:
        
        void run_main_thread_handler(handler_ptr handler, const boost::system::error_code& error)
        {
            handler_ptr_ = handler;
            error_code_ = error;
            ::SendMessage(win_wnd_->m_hWnd,WM_ASIO_MESSAGE,NULL,(LPARAM)this);
        }
    
        void check_deadline()
        {
            if(stop_)return;
            if (deadline_.expires_at() <= deadline_timer::traits_type::now())
            {
                close();
                deadline_.expires_at(boost::posix_time::pos_infin);
            }
            deadline_.async_wait(boost::bind(&MyClassName::check_deadline, this));
        }
    protected:
        CWinWnd* win_wnd_;
        boost::asio::io_service& io_service_;
        tcp::socket socket_;
        tcp::endpoint endpoint_;
        deadline_timer deadline_;
        bool stop_;
        std::size_t connect_timeout_;
    
        handler_ptr handler_ptr_;
        boost::system::error_code error_code_;    
    };

    实际使用时,可以从上面的类中继承:

    class CollectClient : public Win32TcpClient<CTestBoostTimerDlg>
    {
    public:
        CollectClient(boost::asio::io_service& ios,tcp::endpoint endpoint,CTestBoostTimerDlg* pWinWnd):Win32TcpClient<CTestBoostTimerDlg>(ios,endpoint,pWinWnd){ memset(receive_buffer,0,100);}
        virtual void handler_connect(const boost::system::error_code& error);
        virtual void handler_send(const boost::system::error_code& error);
        virtual void handler_receive(const boost::system::error_code& error);
    private:
        char receive_buffer[200] ;
    };
    
    void CollectClient::handler_connect( const boost::system::error_code& error )
    {
        char sendMessage[] = "0020abcdefghijklsdkjaslk";
        if (!error)
        {    
            win_wnd_->MessageBox("success");
            receive(boost::asio::buffer(receive_buffer,30));
            send(boost::asio::buffer(sendMessage,strlen(sendMessage)));
        }
        else
        {    
            win_wnd_->MessageBox("fail");
            if(!stop_)
                close();
        }
    }
    
    void CollectClient::handler_send( const boost::system::error_code& error )
    {
        if(!error)
        {
            //win_wnd_->MessageBox("send success");
        }
        //close();
    }
    
    void CollectClient::handler_receive( const boost::system::error_code& error )
    {
        if(!error)
        {
            win_wnd_->MessageBox(receive_buffer);
            receive(boost::asio::buffer(receive_buffer,30));
        }
        else
        {
            win_wnd_->MessageBox(error.message().c_str());
        
        }
    }

    窗口类中需要添加处理代码是:

    BEGIN_MESSAGE_MAP(CTestBoostTimerDlg, CDialogEx)
        ON_WM_SYSCOMMAND()
        ON_WM_PAINT()
        ON_WM_QUERYDRAGICON()
        ON_MESSAGE(WM_ASIO_MESSAGE,&CTestBoostTimerDlg::OnAsioProc)
    END_MESSAGE_MAP()

    红色为自行添加的消息处理。

    OnAsioProc的代码也是基本固定的。

    声明:

    afx_msg LRESULT OnAsioProc(WPARAM wParam,LPARAM lParam);

    实现:

    LRESULT CTestBoostTimerDlg::OnAsioProc( WPARAM wParam,LPARAM lParam )
    {
        CollectClient* pc = (CollectClient*)lParam;
        pc->win_proc();
        return 0;
    }

    在dialog的初始化OnInitDialog中

    boost::asio::ip::tcp::endpoint endpoint(
            boost::asio::ip::address::from_string("127.0.0.1"), 830);
        pClient = new CollectClient(ios, endpoint,this);
        pClient->connect();

    这里的pClient和ios可以声明为全局变量,或者声明在窗口类中。

    boost::asio::io_service ios;
    CollectClient* pClient;

     为了是异步工作起来,需要启动另一个线程!

    boost::thread th(boost::bind(&io_service::run,&ios));
    th.detach();

    ok,这样的client就可以应用了,关于网络的连接我们其实仅抽象了6个函数connect, handler_connect, send, handler_send, receive, handler_receive。

    还有比较有用的是

      set_timeout 这个函数设置超时的秒数。到这个时间后,socket会自动关闭,默认为inf,不会超时。

      endpoint_ 该变量可查看连接的ip地址和端口号。

      win_wnd_ 该变量为窗口类的指针,可以针对窗口做一系列的操作。

  • 相关阅读:
    Rainmeter 雨滴桌面 主题分享
    行人检測之HOG特征(Histograms of Oriented Gradients)
    const和readonly差别
    ADB命令解析
    Java实现 蓝桥杯VIP 算法训练 接水问题
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
    Java实现 蓝桥杯VIP 算法训练 星际交流
  • 原文地址:https://www.cnblogs.com/zhangyonghugo/p/2614923.html
Copyright © 2011-2022 走看看