boost.asio封裝類st_asio_wrapper開發教程(2013.12.8更新)(二)

來源:互聯網
上載者:User

標籤:

如果你是偶然瀏覽到這裡,請先看 
原始碼及常式:
命令列:svn checkout http://st-asio-wrapper.googlecode.com/svn/trunk/ st-asio-wrapper-read-only
如果從svn用戶端介面上開啟,則只輸入http://st-asio-wrapper.googlecode.com/svn/trunk/到地址欄即可
git:https://github.com/youngwolf-project/st_asio_wrapper/,另外,我的資源裡面也有下載,但不是最新的。
QQ交流群:198941541

六:開發教程(服務端)
服務端直接#include st_asio_wrapper_server.h,就可實現一個簡單的服務端了,如下(還示範了一個echo伺服器,所以繼承st_server寫了個echo_server類):

 

 

//configuration  #define SERVER_PORT     9527  #define REUSE_OBJECT //use objects pool  //#define FORCE_TO_USE_MSG_RECV_BUFFER //force to use the msg recv buffer  #define ENHANCED_STABILITY  //configuration  #include "st_asio_wrapper_server.h"  using namespace st_asio_wrapper;  #define QUIT_COMMAND    "quit"  #define RESTART_COMMAND "restart"  #define LIST_ALL_CLIENT "list_all_client"  #define LIST_STATUS     "status"  #define SUSPEND_COMMAND "suspend"  #define RESUME_COMMAND  "resume"  //demonstrate how to use custom packer  //in the default behavior, every st_tcp_socket has their own packer, and cause memory waste  //at here, we make every echo_socket use the same global packer for memory saving  //notice: do not do this for unpacker, because unpacker has member variables and can‘t share each other  auto global_packer(boost::make_shared<packer>());  //demonstrates how to control the type of st_server_socket_base::server from template parameters  class i_echo_server : public i_server  {  public:  virtual void test() = 0;  };  class echo_socket : public st_server_socket_base<boost::asio::ip::tcp::socket, i_echo_server>  {  public:      echo_socket(i_server& server_) : st_server_socket_base(server_) {inner_packer(global_packer);}  public:  //because we use objects pool(REUSE_OBJECT been defined), so, strictly speaking, this virtual  //function must be rewrote, but we don‘t have member variables to initialize but invoke father‘s  //reset() directly, so, it can be omitted, but we keep it for possibly future using  virtual void reset() {st_server_socket_base::reset();}  protected:  virtual void on_recv_error(const error_code& ec)      {  //the type of st_server_base::server now can be controled by derived class(echo_socket),  //which is actually i_echo_server, so, we can invoke i_echo_server::test virtual function.          server.test();          st_server_socket_base::on_recv_error(ec);      }  //msg handling: send the original msg back(echo server)  #ifndef FORCE_TO_USE_MSG_RECV_BUFFER  //this virtual function doesn‘t exists if FORCE_TO_USE_MSG_RECV_BUFFER been defined  virtual bool on_msg(msg_ctype& msg) {post_msg(msg); return false;}  #endif  //we should handle the msg in on_msg_handle for time-consuming task like this:  virtual void on_msg_handle(msg_ctype& msg) {post_msg(msg);}  //please remember that we have defined FORCE_TO_USE_MSG_RECV_BUFFER, so, st_tcp_socket will directly  //use the msg recv buffer, and we need not rewrite on_msg(), which doesn‘t exist any more  //msg handling end  };  class echo_server : public st_server_base<echo_socket, st_object_pool<echo_socket>, i_echo_server>  {  public:      echo_server(st_service_pump& service_pump_) : st_server_base(service_pump_) {}  //from i_echo_server, pure virtual function, we must implement it.  virtual void test() {/*puts("in echo_server::test()");*/}  };  int main() {      puts("type quit to end these two servers.");      std::string str;      st_service_pump service_pump;      st_server server_(service_pump); //only need a simple server? you can directly use st_server      server_.set_server_addr(SERVER_PORT + 100);      echo_server echo_server_(service_pump); //echo server      service_pump.start_service(1);  while(service_pump.is_running())      {          std::cin >> str;  if (str == QUIT_COMMAND)              service_pump.stop_service();  else if (str == RESTART_COMMAND)          {              service_pump.stop_service();              service_pump.start_service(1);          }  else if (str == LIST_STATUS)          {              printf("normal server:\nvalid links: " size_t_format ", closed links: " size_t_format "\n",                  server_.size(), server_.closed_object_size());              printf("echo server:\nvalid links: " size_t_format ", closed links: " size_t_format "\n",                  echo_server_.size(), echo_server_.closed_object_size());          }  //the following two commands demonstrate how to suspend msg dispatching, no matter recv buffer been used or not  else if (str == SUSPEND_COMMAND)              echo_server_.do_something_to_all(boost::bind(&echo_socket::suspend_dispatch_msg, _1, true));  else if (str == RESUME_COMMAND)              echo_server_.do_something_to_all(boost::bind(&echo_socket::suspend_dispatch_msg, _1, false));  else if (str == LIST_ALL_CLIENT)          {              puts("clients from normal server:");              server_.list_all_object();              puts("clients from echo server:");              echo_server_.list_all_object();          }  else              server_.broadcast_msg(str);          }  return 0;  }  //restore configuration  #undef SERVER_PORT  #undef REUSE_OBJECT //use objects pool  //#undef FORCE_TO_USE_MSG_RECV_BUFFER //force to use the msg recv buffer  #undef ENHANCED_STABILITY  //restore configuration  

 

 

 

        以上例子中,服務端從控制台接收資料,調用broadcast_msg廣播資料;當收到資料時,會輸出到控制台(st_tcp_socket實現);

        其中st_server server_;這行申請了一個普通的服務端,它的功能僅僅是發送接收訊息,接受串連。一般來說,就像教程一裡面的用戶端一樣,需要從st_server_socket繼承一個自己的通訊端類,從st_server繼承一個服務類。為此,服務端demo還示範了一個echo伺服器,它會把收到的任何資料發送回去(大家可以學著做一個echo用戶端,但不要echo服務端與echo用戶端一同工作,否則就死迴圈了。
        start_service開啟服務,stop_service結束服務(退出時必須明確調用),is_running判斷服務的運行狀態;如果想修改服務端地址,則在調用start_service之前調用set_server_addr函數;
        stop_service之後,可再次調用start_service開啟服務;
        注意:st_server的del_client一般用於服務端被動刪除某個client(即在錯誤發生的時候,比如在st_tcp_socket的on_recv_error和on_send_error裡面調用,參看st_server_socket);服務端如果想主動關閉某個client,建議調用這個client的force_close或者graceful_close(st_tcp_socket實現)函數,它們的調用最終會促使on_recv_error的調用;
        st_server的close_all_client主動關閉所有client,比如服務端退出的時候(stop_service會自動調用);
        重寫st_server的on_accept函數,根據你自己的策略確定是否接受用戶端的串連,接受返回true;
        st_server的維護了一個鏈表(st_object_pool實現)用於儲存所有的client(這樣帶幾個好處:一、在廣播訊息的時候,很方便;二、可開啟類似記憶體回收機制的自動清理已經關閉的串連的功能;三、可開啟對象池功能),如果你想自己管理這些client,可以在on_accept裡面返回false,然後把它儲存在自己的容器裡面,並調用start(st_server_socket實現)以便開始接受資料(只調用一次即可);
        當然,你還可以在返回true的同時,自己也儲存一份client(此時就不要再調用start了),這樣做不會帶來多少記憶體消耗,因為它是用智能指標封裝的,複製一份只是增加一個引用計數。至於這樣做有什麼好處,如果你想不到,說明你不需要,當你有需求的時候,你自然而然就會知道有什麼用了,我在這裡只是告訴大家可以這樣做,有個印象即可;
        關於是重寫on_msg還是on_msg_handle,請參看教程第四篇。

boost.asio封裝類st_asio_wrapper開發教程(2013.12.8更新)(二)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.