1. 程式人生 > >基於訊息實現系統間的通訊(BIO,NIO,AIO)學習。

基於訊息實現系統間的通訊(BIO,NIO,AIO)學習。

當系統之間要通訊時,就向外傳送訊息,訊息可以是位元組流,位元組陣列,甚至是java物件,其他系統接受訊息後,則進行相應的業務處理。

訊息方式的系統間通訊,通常基於網路協議來實現,常用的實現系統間的通訊協議有:TCP/IP 和UDP/IP。

TCP/IP是一種可靠的網路資料傳輸協議。TCP/IP要求通訊雙方首先建立連線(通過三次握手協議),之後再進行資料的傳輸。TCP/IP保證資料傳輸的可靠性,包括資料的可到達,資料到達的順序等,如何保證呢?涉及到TCP報文格式,滑動視窗方式的傳輸,超時重傳,選擇確認等計算機網路知識。

UDP/IP是一種不保證資料一點到達的網路資料傳輸協議。UDP/IP並不直接給通訊的雙方建立連線,而是傳送到網路上進行傳遞。由於UDP不建立連線,並且不能保證資料傳輸的可靠,效能表現相當較好,但可能出現數據丟失以及資料亂序的現象。

BIO同步阻塞IO

從程式上來說,就是當發起IO的讀/寫的操作時,均為阻塞方式,只有當讀到了流或將流寫入作業系統後,才會釋放資源。

在這個模型中,使用者級別的應用程式執行一個系統呼叫,這會導致應用程式阻塞。這意味著應用程式會一直阻塞,直到系統呼叫完成為止(資料傳輸完成或發 生錯誤)。呼叫應用程式處於一種不再消費 CPU 而只是簡單等待響應的狀態。

以read位例,應用程式(application)為了執行這個read操作,會呼叫相應的一個system call,將系統控制權交給kernel,然後就進行等待(這其實就是被阻塞了)。kernel開始執行這個system call,執行完畢後會嚮應用程式返回響應,應用程式得到響應後,就不再阻塞,並進行後面的工作。

如上圖,“在呼叫 read 系統呼叫時,應用程式會阻塞並對核心進行上下文切換。然後會觸發讀操作,當響應返回時(從我們正在從中讀取的裝置中返回),資料就被移動到使用者空間的緩衝區中。然後應用程式就會解除阻塞(read 呼叫返回)。”

同步非阻塞IO (NIO)

NIO是基於事件驅動思想的,實現上通常採用Reactor(http://en.wikipedia.org/wiki/Reactor_pattern)模式,從程式角度而言,當發起IO的讀或寫操作時,是非阻塞的;當socket有流可讀或可寫入socket時,作業系統會相應的通知引用程式進行處理,應用再將流讀取到緩衝區或寫入作業系統。對於網路IO而言,主要有連線建立、流讀取及流寫入三種事件、linux2.6以後的版本使用epoll(

http://lse.sourceforge.net/epoll/index.html)方式實現NIO。

select/epoll的好處就在於單個process就可以同時處理多個網路連線的IO。它的基本原理就是select/epoll這個function會不斷的輪詢所負責的所有socket,當某個socket有資料到達了,就通知使用者程序。它的流程如圖:

當用戶程序呼叫了select,那麼整個程序會被block,而同時,kernel會“監視”所有select負責的socket,當任何一個socket中的資料準備好了,select就會返回。這個時候使用者程序再呼叫read操作,將資料從kernel拷貝到使用者程序。
這個圖和blocking IO的圖其實並沒有太大的不同,事實上,還更差一些。因為這裡需要使用兩個system call (select 和 recvfrom),而blocking IO只調用了一個system call (recvfrom)。但是,用select的優勢在於它可以同時處理多個connection。(多說一句。所以,如果處理的連線數不是很高的話,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server效能更好,可能延遲還更大。select/epoll的優勢並不是對於單個連線能處理得更快,而是在於能處理更多的連線。)
在IOmultiplexing Model中,實際中,對於每一個socket,一般都設定成為non-blocking,但是,如上圖所示,整個使用者的process其實是一直被block的。只不過process是被select這個函式block,而不是被socket IO給block。

AIO,非同步IO方式

從程式的角度而言,與NIO不同,當進行讀寫操作時,只須直接呼叫API的read或write方法即可。這兩種方法均為非同步的,對於讀操作而言,當有流可讀取時,作業系統會將可讀的流傳入read方法的緩衝區,並通知應用程式;對於寫操作而言,當作業系統將write方法傳遞的流寫入完畢時,作業系統主動通知應用程式。較之NIO而言,AIO一方面簡化了程式出的編寫,流的讀取和寫入都由作業系統來代替完成;另一方面省去了NIO中程式要遍歷事件通知佇列(selector)的代價。Windows基於IOCP(http://en.wikipedia.org/wiki/Input/output_completion_port)實現了AIO,Linux目前只有基於epoll實現的AIO。