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

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

編輯:C++入門知識

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


io_service類 你應該已經發現大部分使用Boost.Asio編寫的代碼都會使用幾個ios_service的實例。ios_service是這個庫裡面最重要的類;它負責和操作系統打交道,等待所有異步操作的結束,然後為每一個異步操作調用完成處理程序。 如果你選擇用同步的方式來創建你的應用,你不需要考慮我將在這一節向你展示的東西。 你可以用幾種不同的方式來使用io_service。在下面的例子中,我們有3個異步操作,2個socket連接和一個計時器等待: 有一個io_service和一個處理線程的單線程例子: io_service service_;
// all the socket operations are handled by service_
ip::tcp::socket sock1(service_);
// all the socket operations are handled by service_
ip::tcp::socket sock2(service_);
sock1.async_connect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service_, boost::posix_time::seconds(5));
t.async_wait(timeout_handler);
service_.run();
有單個io_service實例和多個處理線程的多線程例子: io_service service_;
ip::tcp::socket sock1(service_);
ip::tcp::socket sock2(service_);
sock1.async_connect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service_, boost::posix_time::seconds(5));
t.async_wait(timeout_handler);
for ( int i = 0; i < 5; ++i)
boost::thread( run_service);
void run_service() {
service_.run();
}
有多個io_service實例和多個處理線程的多線程例子: io_service service_[2];
ip::tcp::socket sock1(service_[0]);
ip::tcp::socket sock2(service_[1]);
sock1.async_connect( ep, connect_handler);
sock2.async_connect( ep, connect_handler);
deadline_timer t(service_[0], boost::posix_time::seconds(5));
t.async_wait(timeout_handler);
for ( int i = 0; i < 2; ++i)
boost::thread( boost::bind(run_service, i));
void run_service(int idx) {
service_[idx].run();
}
首先,要注意你不能擁有多個io_service卻只有一個線程。下面的代碼片段沒有任何意義: for ( int i = 0; i < 2; ++i)
service_[i].run();
上面的代碼片段沒有意義是因為service_[1].run()需要service_[0].run()先結束。因此,所有由service_[1]處理的異步操作都需要等待,這顯然不是一個好主意。 在前面的3個方案中,我們在等待3個異步操作結束。為了解釋之間的不同點,我們假設:過一會操作1完成,然後接著操作2完成。同時我們假設每一個完成處理程序需要1秒鐘來完成執行。 在第一個例子中,我們在一個線程中等待三個操作全部完成,只要第1個操作完成,我們調用它的完成處理程序。盡管操作2緊接著完成了,操作2的完成處理程序需要在1秒鐘後操作1的完成處理程序完成才被調用。 第二個例子,我們在兩個線程中等待3個異步操作結束。當操作1完成時,我們在第一個線程中調用它的完成處理程序。當操作2完成時,緊接著,我們就在第二個線程中調用它的完成處理函數(當線程1在忙著響應操作1的處理程序時,線程2空閒著並且可以回應任何新進來的操作)。 在第三個例子中,因為操作1是sock1的connect,操作2是sock2的connect,所以應用程序會表現得像第二個例子一樣。線程1會處理sock1 connect操作的完成處理程序,線程2會處理sock2的connect操作的完成處理程序。然而,如果sock1的connect操作是操作1,deadline_timer t的超時操作是操作2,線程1會結束正在處理的sock1 connect操作的完成處理程序。因而,deadline_timer t的超時操作必須等sock1 connect操作的完成處理程序結束(等待1秒鐘),因為線程1要處理sock1的連接處理程序和t的超時處理程序。 下面是你需要從前面的例子中學到的: 第一種情況是非常基礎的應用程序。因為是串行的方式,所以當幾個處理程序要被同時調用時,你會經常遇到瓶頸。如果一個處理程序需要花費很長的時間來執行,所有隨後的處理程序都不得不等待。 第二種情況是比較適用的應用程序。他是非常強壯的——如果幾個處理程序被同時調用了(這是有可能的),它們會在各自的線程裡面被調用。唯一的瓶頸就是所有的處理線程都很忙的同時又有新的處理程序被調用。然而,這有快速的解決方式,增加處理線程的數目即可。 第三種情況最復雜和最難理解的。你只有在第二種情況不能滿足需求時才使用它。這種情況一般就是當你有成千上萬實時(socket)連接時。你可以認為每一個處理線程(運行io_service::run()的線程)有它自己的select/epoll循環;它等待任何一個socket,然後監控一個讀寫操作,當它發現這種操作時,就執行。大部分情況下,你不需要擔心什麼,唯一你需要擔心的就是當你監控的socket數目以指數級的方式增長時(超過1000個的socket)。在那種情況下,有幾個select/epoll循環會增加響應時間。
如果你覺得你成應用程序可能需要轉換到第三種模式,請確保監聽操作的這段代碼(調用io_service::run()的代碼)和應用程序其他部分是隔離的,這樣你就可以很輕松的對其進行更改。 最後,要一直記住如果沒有其他需要監控的操作,.run()就會結束,就像下面給的代碼片段: io_service service_;
tcp::socket sock(service_);
sock.async_connect( ep, connect_handler);
service_.run();
在上面的例子,只要sock建立了一個連接,connect_handler就會被調用,然後接著service_.run()就會完成執行。 如果你想要service_.run()接著執行,你需要分配更多的工作給它。這裡有兩個方式來完成這個目標。一種方式是在connect_handler中啟動另外一個異步操作來分配更多的工作。 另一種方式模擬一些工作給它,用下面的代碼片段: typedef boost::shared_ptr work_ptr;
work_ptr dummy_work(new io_service::work(service_));
上面的代碼可以保證service_.run()一直運行直到你調用useservice_.stop()或者 dummy_work.reset(0);// 銷毀 dummy_work.
總結 Boost.Asio是一個復雜的庫,但是卻讓網絡編程變得異常簡單。編譯它很簡單。它避免使用宏,這一點做得很好;他雖然定義了少部分的宏來做選項開關,但是你需要擔心的很少。 Bosot.Asio支持同步和異步編程。他們有很大不同;你需要早早地選擇其中的一種,因為它們之間的轉換是非常復雜而且易錯的。 如果你選擇同步,你可以選擇異常處理或者錯誤碼,從異常處理轉到錯誤碼;只需要在call函數中增加一個參數即可(錯誤碼)。 Boost.Asio不僅僅可以用來做網絡編程。它還有其他更多的特性,這讓它顯得更有價值,比如信號量,計時器等等。 下一章我們將深入研究大多數Boost.Asio中用來做網絡編程的函數和類。同時我們也會學一些異步編程的訣竅。

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