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_前綴,按照異步方式執行;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章