程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Boost.Asio c++ 網絡編程翻譯(14)

Boost.Asio c++ 網絡編程翻譯(14)

編輯:C++入門知識

Boost.Asio c++ 網絡編程翻譯(14)


保持活動 假如,你需要做下面的操作: io_service service; ip::tcp::socket sock(service); char buff[512]; ... read(sock, buffer(buff)); 在這個例子中,sock和buff的存在時間都必須比read()調用的時間要長。也就是說,在調用read()返回之前,它們都必須有效。這就是你期望的;你傳給一個方法的所有參數在參數內部都必須有效。當我們采用異步方式時,事情會變得越復雜。 io_service service; ip::tcp::socket sock(service); char buff[512]; void on_read(const boost::system::error_code &, size_t) {} ... async_read(sock, buffer(buff), on_read); 在這個例子中,sock和buff的存在時間都必須比read()操作本身時間要長,但是read操作的時間我們是不知道的,因為它是異步的。 當使用socket緩沖區的時候,你會有一個buffer實例在異步調用時一直存在(使用boost::shared_array<>)。在這裡,我們可以使用同樣的方式,通過創建一個類並在其內部管理socket和它的讀寫緩沖區。然後,對於所有的異步操作,我會傳遞一個包含智能指針的boost::bind仿函數:
using namespace boost::asio;
   io_service service;
   struct connection : boost::enable_shared_from_this {
       typedef boost::system::error_code error_code;
       typedef boost::shared_ptr ptr;
       connection() : sock_(service), started_(true) {}
       void start(ip::tcp::endpoint ep) {
           sock_.async_connect(ep,
                 boost::bind(&connection::on_connect, shared_from_this(),

_1)); }

       void stop() {
           if ( !started_) return;
           started_ = false;
           sock_.close();

}

       bool started() { return started_; }
   private:
       void on_connect(const error_code & err) {
           // here you decide what to do with the connection: read or
   write
           if ( !err)      do_read();
           else            stop();
       }
       void on_read(const error_code & err, size_t bytes) {
           if ( !started() ) return;
           std::string msg(read_buffer_, bytes);
page64image11240
if ( msg == "can_login")
else if ( msg.find("data ") == 0)
else if ( msg == "login_fail")
do_write("access_data");
process_data(msg);
stop();
}
void on_write(const error_code & err, size_t bytes) {

do_read(); }

void do_read() {
           sock_.async_read_some(buffer(read_buffer_),
                 boost::bind(&connection::on_read, shared_from_this(),

_1, _2)); }

       void do_write(const std::string & msg) {
           if ( !started() ) return;
           // note: in case you want to send several messages before
           //       doing another async_read, you'll need several write
   buffers!
           std::copy(msg.begin(), msg.end(), write_buffer_);
           sock_.async_write_some(buffer(write_buffer_, msg.size()),
                 boost::bind(&connection::on_write, shared_from_this(),

_1, _2)); }

       void process_data(const std::string & msg) {
           // process what comes from server, and then perform another

write }

   private:
       ip::tcp::socket sock_;
       enum { max_msg = 1024 };
       char read_buffer_[max_msg];
       char write_buffer_[max_msg];
       bool started_;

};

   int main(int argc, char* argv[]) {
       ip::tcp::endpoint ep( ip::address::from_string("127.0.0.1"),
   8001);
       connection::ptr(new connection)->start(ep);

}

在所有異步調用中,我們傳遞一個boost::bind仿函數當作參數。這個仿函數內部包含了一個智能指針,指向connection實例。只要有一個異步操作等待時,Boost.Asio會保存boost::bind仿函數的拷貝,這個拷貝保存了指向連接實例的一個智能指針,從而保證connection實例保持活動。問題解決!

當然,connection類僅僅是一個skeleton類;你需要根據你的需求對它進行調整(它看起來會和服務端的情況相當不同)。

你需要注意創建一個新的連接是相當簡單的:connection::ptr(new connection)- >start(ep)。這個方法啟動了到服務端的(異步)連接。當你需要關閉這個連接時,調用stop()。

當實例被啟動時(start()),它將會等待被連接。當連接發生時。on_connect()被調用。如果沒有錯誤發生,它啟動一個read操作(do_read())。當read操作結束時,你解析這個消息;你應用的on_read()看起來會各種各樣。當你寫回一個消息時,你需要把它拷貝到緩沖區,然後像我在do_write()方法中所做的一樣將其發送出去,因為再一次,這個緩沖區需要在這個異步寫操作中一直存活。最後需要注意的一點——當寫回時,你需要指定寫入的數量,否則,整個緩沖區都會被發送出去。

總結

網絡api實際上要大得多,這個章節只是一個參考,當你在實現你自己的網絡應用時,你需要回來查看。

Boost.Asio實現了端點的概念,你可以認為是IP和端口。如果你不知道准確的IP,你可以使用resolver對象將主機名,例如www.yahoo.com轉換為一個或多個IP地址。

我們也可以看到API的核心——socket類。Boost.Asio提供了TCP、UDP和 ICMP的實現。但是你可以用你自己的協議來對它進行擴展;當然,這個工作不適合膽小的人。

異步編程是必要之惡。你會明白為什麼有時候需要它,尤其在寫服務端的時候。調用service.run()來實現異步循環就已經可以讓你很開心,但是有時候你需要更進一步,嘗試使用run_one()、poll()或者poll_one()。

當實現異步時,你可以用你自己方法來異步執行;使用service.post()或者service.dispatch()。

最後,為了使socket和緩沖區(read或者write)在整個異步操作的生命周期中一直活動,我們需要采取特殊的防護措施。你的連接類需要繼承自enabled_shared_from_this,在內部保存它需要的緩沖區,而且每個異步調用都要傳遞一個智能指針給this操作。

下一章會讓你進行實戰操作;在實現回顯客戶端/服務端應用時會有大量的上手編程。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved