[Boost] ASIO學習筆記:network basic– UDP Server

posted in: ASIO, boost, C/C++程式設計, Server | 0

UDP  Server跟TCP Server不同,它是屬於connectionless的技術,因此不需要acceptor去跟client建立連線的步驟。我們只需要利用socket去bind特定的port後,就可以接收到資料。 一個Sync socket的流程如下,圖片引用自此: 在ASIO中的Server端程式碼: #include <boost/asio.hpp> #include <boost/shared_ptr.hpp> #include <boost/bind.hpp> #include <iostream> #include <string> #include <boost/thread.hpp> using namespace std; void main(){ boost::system::error_code ec; boost::shared_ptr<boost::asio::io_service> io_service(new boost::asio::io_service); boost::shared_ptr<boost::asio::io_service::strand> strand(new boost::asio::io_service::strand(*io_service)); // boost::shared_ptr< boost::asio::io_service::work > work(new boost::asio::io_service::work( *io_service )); try{ … Continued

[Boost] ASIO學習筆記:network basic– TCP Server

posted in: ASIO, boost, C/C++程式設計, Server | 0

在上一篇[Boost] ASIO學習筆記:network basic – client有展示了該怎麼撰寫一個client去連接一個遠端的Server,而在本篇,將會接著介紹怎麼利用ASIO撰寫一個Server來處理與client端的連接。 首先在Server端開始運行之前,最重要的事便是決定要與哪個port綁定並監聽是否有資料傳送進來。只是,到底什麼是port呢?port是範圍定在0~65535之間的號碼,為Client跟Server之間連接的管道。打個比喻來說:如果ip是電話號碼的話,那麼port便是一個公司(Server)的分機號碼。port所定義的,是Client要打哪個分機號碼才能得公司(Server)所提供的服務。 其中: 0~1023為公認埠(Well Known Ports),通常用於某些特定的系統程序或者是常用的網路協定上。例如80為http、21為ftp、23為telnet…等等。 1024~49151為註冊埠(Registered Ports):理論上要使用該port來提供服務的公司要跟IANA是出申請,但實際上我們也常常拿來做動態或私人用途。 49152~65535為動態和/或私有埠(Dynamic and/or Private Ports):通常是拿來當作臨時或特定客製化的需求時使用。 其實,在撰寫程式的時候,我們可以去監聽任何的port,下圖為TCP Server操作的流程圖(下圖引自wiki,我們可以看到ASIO完全遵照Berkeley sockets API進行封裝): 以下為一個最簡單監聽port 12345的serve程式: #include <boost/asio.hpp> #include <boost/shared_ptr.hpp> #include <boost/bind.hpp> #include <iostream> #include <string> #include <boost/thread.hpp> using namespace std; void onAcceptEvent(boost::system::error_code ec, … Continued

[Boost] ASIO學習筆記:network basic – client

posted in: ASIO, boost, C/C++程式設計, Server, 遊戲 | 0

對於網路程式設計而言,不外乎是server或者是client程式這二種。 而怎麼讓二台遠端的電腦透過網路溝通的程式設計,稱作socket programming。 現在就讓我們先從最基本的client端連接到遠端server的程式開始: #include <boost/asio.hpp> #include <boost/shared_ptr.hpp> #include <iostream> #include <string> using namespace std; int main( int argc, char * argv[] ) { boost::shared_ptr< boost::asio::io_service > io_service(new boost::asio::io_service); boost::asio::ip::tcp::socket sock( *io_service ); boost::asio::ip::tcp::resolver resolver(*io_service); boost::asio::ip::tcp::resolver::query query( “www.yahoo.com.tw”, “80”); boost::asio::ip::tcp::resolver::iterator … Continued

[Boost] ASIO學習筆記:使用strand來serializing thread

posted in: ASIO, boost, C/C++程式設計 | 0

[insert page=’151′ display=’link’],我們知道在多條thread的程式設計中,對於執行的結果我們是無法預期的。雖然使用mutex可以保證thread-safety,但卻無法保證工作能夠照我們所期望的順序執行。 在boost ASIO中提供了strand來解決既能保證thread-safety又能夠讓工作的順序能夠依照post的順序執行。執行並觀察以下的程式結果: boost::mutex global_stream_lock; void WorkerThread( boost::shared_ptr< boost::asio::io_service > io_service ){ global_stream_lock.lock(); std::cout < < “[” << boost::this_thread::get_id() << “] Thread Start” << std::endl; global_stream_lock.unlock(); io_service->run(); global_stream_lock.lock(); std::cout < < “[” << boost::this_thread::get_id() << “] Thread Finish” … Continued

[Boost] ASIO學習筆記:post and dispatch

posted in: ASIO, boost, C/C++程式設計 | 0

對於io_service之中,最重要的莫過於post跟dispatch這二個功能。到底這二個功能有何異同呢? post:指的是將一個工作加入Completion Event Queue裡面dispatch:若是在被run()或poll()所回呼的handler,則馬上執行指派的工作,若是在main()的線程中,則效力與post相同。 試著執行以下程式可以看到二個函式的不同: boost::mutex global_stream_lock; void Dispatch( int x ){ global_stream_lock.lock(); std::cout < < “[” << boost::this_thread::get_id() << “] ” << __FUNCTION__ << ” x = ” << x << std::endl; global_stream_lock.unlock(); } void Post( int x ){ … Continued

[boost]ASIO學習筆記:Sync/Async、Blocking/Non-Blocking IO

posted in: ASIO, boost, C/C++程式設計 | 0

關於四種名詞的詳細內容可以參閱本篇連結 其實這四個名詞在概念上有一些微妙的差別,Sync/Async IO的差別在於程式是否要去等待OS的IO操作結束:在boost中是指io_service選用了run()或者是poll(),會進行kernel context switch到OS kernel來運行。而Blocking/Non-Blocking則是指我們是否要等待程式執行流程中的IO結束才能繼續執行,主要是由application來實作、設計執行的機制。 其實一個程式是不是Sync/Asyn或blocking/non-blocking,其實看的是一段程式碼或者是一個function 通常如果該段程式碼包含while迴圈來判斷某個檔案是狀態,那麼就是blocking,但如果這時候又程式thread來分配該任務的執行,那麼就是non-blocking。 在non-blocking的程式中,如果有牽扯到檔案的讀寫問題,那麼我們就必須在程式中撰寫一些機制去確認該檔案是如已經可以寫入,以必免造成race condition的情況。通常依照不同的作業系統會使用poll、select、epoll、iocp等機制。 關於poll、select、epoll等分別請參閱本篇 在boost::ASIO中,由於為了要達成跨平台,因此在背後實作了Proactor模式來隱藏細節,並以Reactor來實作不同平台的機制。我們可以利用以下的程式碼印出我們的作業系統所採用的是那一種: #include <iostream> #include <string> #include <boost/asio.hpp> int main() { std::string output; #if defined(BOOST_ASIO_HAS_IOCP) output = “iocp” ; #elif defined(BOOST_ASIO_HAS_EPOLL) output = “epoll” ; #elif defined(BOOST_ASIO_HAS_KQUEUE) output = “kqueue” … Continued

[Boost] ASIO學習筆記:thread及Synchronization

posted in: ASIO, boost, C/C++程式設計 | 0

我們知道,我們無法預測thread執行的先後,這代表的是任何一個thread都有可以在任何的時間點從CPU上取得操作權。這不僅會造成cout時文字無法連續,同時在操作資料時,最害怕的情形是『同時』有多個thread去對『同一個資料』做更改,因為他會造成運算結果的錯誤。這個特性,在電腦科學裡面稱作race condition,進而導致了需要保證thread-safety的問題。 在boost裡提供了mutex機制來解決(Critical Section Problem) 一個簡單的demo: #include <boost/thread.hpp> #include <iostream> void wait(int seconds) { boost::this_thread::sleep(boost::posix_time::seconds(seconds)); } boost::mutex mutex; int gValue = 0; void thread(int i) { wait(1); mutex.lock(); gValue = gValue + i; std::cout < < “Thread :” << boost::this_thread::get_id() … Continued

[Boost] ASIO學習筆記:bind and ASIO

posted in: ASIO, boost, C/C++程式設計 | 0

boost::bind的功用,主要是將function變成function object(functor)來當成參數傳送,其目的,最主要是用來實現系統callback的功能。以下為一個簡單的小程式: #include <boost/asio.hpp> #include <boost/shared_ptr.hpp> #include <boost/thread.hpp> #include <iostream> using namespace std; boost::asio::io_service io_service; void WorkerThread(int x){ std::cout < < “Thread Start:” << x << endl; io_service.run(); std::cout << “Thread Finish:” << x << endl; } int main( int … Continued

[Boost] ASIO學習筆記:thread

posted in: ASIO, boost, C/C++程式設計, 遊戲 | 1

在前面的例子中,我們都是以single thread來執行,但在同步/非同步操作中,其實很多問題都需要multi-thread來解決,例如,多人的連線遊戲,就需要多條thread來配給每一個不同的連線。 在進行之前,我們必須要知道的是process跟thread的分別: 當我們在執行一個程式之後,就會產生一個process,這個process擁有以下二種東西: 1.自己的Memory space 2.一個以上的thread 而每一個thread又擁有以下二個東西: 1.Stack:紀錄函數呼叫路徑,以及這些函數所用到的區域變數(local variable) 2.目前CPU的狀態 由於thread有自己的stack,因此每個thread雖然共享同一個Memory space可以存取到彼此之間的物件,但卻無法存取到對方的local variable 由於thread只是多工而不是平行運算,因此OS會依照thread所設定的優先權,分配相應的時間讓其使用CPU。例如:當我們在玩遊戲的時候,遊戲程式執行後會產生一個process,而這個process中會有如播放音樂、更新畫面…等許多的任務,這時候我們可以分配不同的thread去執行並分配其優先順序 創建、分配thread及其優先順序通常是程式設計師自己要寫,當我們使用遊戲引擎如OGRE、hge等來寫遊戲的話,如果沒特別導入如boost::thread這類的函式庫的話,其實都會是single thread的程式,也就是說,我們必須讀完所有的resource才能進行遊戲,不能夠一邊讀resource一邊顯示讀檔的進度。 基本上,當一個程式開始執行的時候,他只會存在一個執行main() function的thread,使用multi-thread的重要性在於,除了他能夠做到以上的事情之外,更重要的是,由於現在的電腦都擁有1顆以上的CPU,因此我們可以更進一步的分配這些thread給不同的CPU來運算 以下展示了一個簡單的boost::thread程式: void thread(const char* name) { for (int i = 0; i < 5; ++i) { std::cout << name << std::endl; … Continued

[Boost] ASIO學習筆記:初探io_service

posted in: ASIO, boost, C/C++程式設計 | 0

ASIO的實現,其實就是基於Proactor pattern,在這裡我們先不對這個pattern做探討,等以後有機會再來談 想像io_service即是os跟我們程式之間的橋梁,當執行io_service.run()的時候,便是將系統轉移到os上,並block住原本的程式,直至所有的工作佇列完成,其是一種synchronous 模式。 只是,有時候我們並不希望程式在完成工作之後就結束,而是繼續等待是否有其他工作傳入,這時候我們就可以加入boost::asio::io_service::work work( io_service );,以便讓系統能夠持續的運行。 完整程式碼如下: #include <boost/asio.hpp> #include <iostream> int main( int argc, char * argv[] ){ boost::asio::io_service io_service; boost::asio::io_service::work work( io_service ); io_service.run(); std::cout < < “這行永遠到不了” << std::endl; return 0; } 為什麼會這樣呢?那是因為work object 提供一個work給 … Continued