『壹』 安卓IPC跨進程通訊:AIDL+Retrofit——AndLinker的初步使用
需要用到安卓跨進程通訊,IPC (進程間通信) 的時候,AndLinker是一款android上的IPC (進程間通信) 庫,結合了 AIDL 和 Retrofit 的諸多特性,且可以與 Rxjava 和 RxJava2 的Call Adapters無縫結合使用。
個人簡單理解就是:簡化AIDL流程的一個第三方庫。使用時需要先了解一下AIDL、retrofit。
以普通Java介面代替AIDL介面
像 Retrofit 一樣生成遠程服務介面的IPC實現
支持的Call Adapters:Call, RxJava Observable, RxJava2 Observable & Flowable
支持遠程服務回調機制
支持AIDL的所有數據類型
支持AIDL的所有數據定向tag:in,out,inout
支持AIDL的oneway關鍵字
在服務端以及客戶端的項目根目錄的build.gradle中添加jcenter()倉庫
在App的build.gradle中添加如下依賴
AndLinker支持AIDL所有數據類型:
Java語言中的所有原始類型 (如:int,long,char,boolean,等等)
String
CharSequence
Parcelable
List (List中的所有元素必須是此列表中支持的數據類型)
Map (Map中的所有元素必須是此列表中支持的數據類型)
介面里的方法就是按需求需創建。這里只舉幾個簡單的示例。
『貳』 Carson帶你學Android:全面剖析Binder跨進程通信原理
從而全方位地介紹 Binder ,希望你們會喜歡。
在本文的講解中,按照 大角度 -> 小角度 去分析 Binder ,即:
從而全方位地介紹 Binder ,希望你們會喜歡。
在講解 Binder 前,我們先了解一些 Linux 的基礎知識
具體請看文章: 操作系統:圖文詳解 內存映射
Binder 跨進程通信機制 模型 基於 Client - Server 模式
此處重點講解 Binder 驅動作用中的跨進程通信的原理:
原因:
所以,原理圖可表示為以下:
所以,在進行跨進程通信時,開發者只需自定義 Client & Server 進程 並 顯式使用上述3個步驟,最終藉助 Android 的基本架構功能就可完成進程間通信
注冊服務後, Binder 驅動持有 Server 進程創建的 Binder 實體
此時, Client 進程與 Server 進程已經建立了連接
Client 進程 根據獲取到的 Service 信息( Binder 代理對象),通過 Binder 驅動 建立與 該 Service 所在 Server 進程通信的鏈路,並開始使用服務
步驟1: Client 進程 將參數(整數a和b)發送到 Server 進程
步驟2: Server 進程根據 Client 進要求 調用 目標方法(即加法函數)
步驟3: Server 進程 將目標方法的結果(即加法後的結果)返回給 Client 進程
對比 Linux ( Android 基於 Linux )上的其他進程通信方式(管道、消息隊列、共享內存、
信號量、 Socket ), Binder 機制的優點有:
特別地,對於從模型結構組成的Binder驅動來說:
不定期分享關於 安卓開發 的干貨,追求 短、平、快 ,但 卻不缺深度 。
『叄』 Android跨進程通信-共享內存
還是先看共享內存的使用方法,我主要介紹兩個函數:
通過 shmget() 函數申請共享內存,它的入參如下
通過 shmat() 函數將我們申請到的共享內存映射到自己的用戶空間,映射成功會返回地址,有了這個地址,我們就可以隨意的讀寫數據了,我們繼續看一下這個函數的入參
共享內存的原理是在內存中單獨開辟的一段內存空間,這段內存空間其實就是一個tempfs(臨時虛擬文件),tempfs是VFS的一種文件系統,掛載在/dev/shm上,前面提到的管道pipefs也是VFS的一種文件系統。
由於共享的內存空間對使用和接收進程來講,完全無感知,就像是在自己的內存上讀寫數據一樣,所以也是 效率最高 的一種IPC方式。
上面提到的IPC的方式都是 在內核空間中開辟內存來存儲數據 ,寫數據時,需要將數據從用戶空間拷貝到內核空間,讀數據時,需要從內核空間拷貝到自己的用戶空間,
共享內存就只需要一次拷貝 ,而且共享內存不是在內核開辟空間,所以可以 傳輸的數據量大 。
但是 共享內存最大的缺點就是沒有並發的控制,我們一般通過信號量配合共享內存使用,進行同步和並發的控制 。
共享內存在Android系統中主要的使用場景是 用來傳輸大數據 ,並且 Android並沒有直接使用Linux原生的共享內存方式,而是設計了Ashmem匿名共享內存 。
之前說到有名管道和匿名管道的區別在於有名管道可以在vfs目錄樹中查看到這個管道的文件,但是匿名管道不行, 所以匿名共享內存同樣也是無法在vfs目錄中查看到 的, Android之所以要設計匿名共享內存 ,我覺得主要是為了安全性的考慮吧。
我們來看看共享內存的一個使用場景,在Android中,如果我們想要將當前的界面顯示出來,需要將當前界面的圖元數據傳遞Surfaceflinger去做圖層混合,圖層混合之後的數據會直接送入幀緩存,送入幀緩存後,顯卡就會直接取出幀緩存里的圖元數據顯示了。
那麼我們如何將應用的Activity的圖元數據傳遞給SurfaceFlinger呢?想要將圖像數據這樣比較大的數據跨進程傳輸,靠binder是不行的,所以這兒便用到匿名共享內存。
從谷歌官方提供的架構圖可以看到,圖元數據是通過BufferQueue傳遞到SurfaceFlinger去的,當我們想要繪制圖像的時候, 需要從BufferQueue中申請一個Buffer,Buffer會調用Gralloc模塊來分配共享內存 當作圖元緩沖區存放我們的圖元數據。
可以看到Android的匿名共享內存是通過 ashmem_create_region() 函數來申請共享內存的,它會在/dev/ashmem下創建一個虛擬文件,Linux原生共享內存是通過shmget()函數,並會在/dev/shm下創建虛擬文件。
匿名共享內存是通過 mmap() 函數將申請到的內存映射到自己的進程空間,而Linux是通過*shmat()函數。
雖然函數不一樣,但是Android的匿名共享內存和Linux的共享內存在本質上是大同小異的。
要使用一塊共享內存
『肆』 Android 使用Messenger實現跨進程之間通信
以前講到跨進程通信,我們總是第一時間想到AIDL(Android介面定義語言),實際上,使用Messenger在很多情況下是比使用AIDL簡單得多的。
大家看到Messenger可能會很輕易的聯想到Message,然後很自然的進一步聯想到Handler——沒錯,Messenger的核心其實就是Message以及Handler來進行線程間的通信。
以下是如何使用Messenger的步驟:
綜上六步就能完成客戶端與Service的跨進程雙向通信過程:
客戶端 -> Service -> 客戶端
簡單的例子(客戶端向伺服器端發送消息,伺服器接收):
服務端主要是返給客戶端一個IBinder實例,以供服務端構造Messenger,並且處理客戶端發送過來的Message。當然,不要忘了要在Manifests文件裡面注冊.
客戶端就主要是發起與服務端的綁定,以及通過onServiceConnected()方法來過去服務端返回來的IBinder,藉此構造Messenger,從而可以通過發送Message的方式與服務端進行交互。
伺服器接收消息後回復消息給客戶端
客戶端修改:
客戶端需要添加一個handler用於接收消息
服務端修改:
在服務端的handler獲取客戶端發送的msg.replyTo
『伍』 利用Messenger跨進程通信
Android筆記多進程通信之利用Messenger跨進程通信,
提起跨進程通信,大多數人首先會想到AIDL,AIDL,中文名稱是android介面描述語言,是android系統中用於進行跨進程通信必須了解的。其實messenger和AIDL作用一樣,都可以進行進程間通訊。它是基於消息的進程間通信,通過構建Message來在客戶端和服務端之間傳遞數據,就像Handler發送消息在子線程和UI線程發送消息那樣,還不用去寫AIDL文件。
Messenger翻譯為信使,可以在不同進程中傳遞Message對象,在Message中放入我們需要傳遞的信息,然後通過Messenger將Message傳遞給對方,就可以輕輕鬆鬆實現跨進程數據傳遞。實際上Messenger是一種輕量級的IPC(跨進程通信)方式,它的底層仍然是實現的AIDL。
此外,還支持記錄客戶端對象的Messenger,然後可以實現一對多的通信;甚至作為一個轉接處,任意兩個進程都能通過服務端進行通信。
相同點:
1.都與IPC的調用有關;
2.Messenger 是一種輕量級的 IPC方案,底層實現了AIDL,只是進行了封裝,開發的時候不用寫.aidl文件。
3.都支持實時通信;
不同點:
1. Messenger一次只能處理一個請求(串列)/AIDL一次可以處理多個請求(並行);
當您需要執行 IPC 時,為您的介面使用 Messenger 要比使用 AIDL 實現更加簡單,因為 Messenger 會將所有服務調用排入隊列,而純粹的 AIDL 介面會同時向服務發送多個請求,服務隨後必須應對多線程處理。
對於大多數應用,服務不需要執行多線程處理,因此使用 Messenger 可讓服務一次處理一個調用。如果您的服務必須執行多線程處理,則應使用 AIDL 來定義介面。
2. Messenger不支持RPC,只能通過message傳遞消息/AIDL支持RPC;
3. Messenger使用簡單,輕量級,不需要創建AIDL文件/AIDL使用復雜,需要創建AIDL文件;
服務端:
1.創建一個handler對象,並實現hanlemessage方法,用於接收來自客戶端的消息,並作處理
2.創建一個messenger,封裝handler
3.用messenger的getBinder()方法獲取一個IBinder對象,通過onBind返回給客戶端
客戶端:
1.在activity中綁定服務
2.創建ServiceConnection並在其中使用 IBinder 將 Messenger實例化
3.使用Messenger向服務端發送消息,或需要伺服器端返回消息,需要創建一個messenger,封裝handler,並將這個messenger傳遞給伺服器端。在handler中接收伺服器消息。這樣就實現了客戶端和服務端的雙向通信了。
4.解綁服務
5.服務端中在 handleMessage() 方法中接收每個 Message
創建一個service
注冊service,當然要設置在不同的進程
注意:Service在聲明時必須對外開放,即android:exported="true"
客戶端是通過綁定服務端返回的binder來創建Messenger對象,並通過這個Messenger對象來向服務端發送消息。
總結
Message中的Bundle支持多種數據類型,replyTo欄位用於傳輸Messager對象,以便進程間相互通信
Messager以串列的方式處理客戶端發來的消息,不適合有大量並發的請求
Messager方法只能傳遞消息,不能跨進程調用方法
『陸』 了解Android進程間通信的四種方式
由於應用程序之間不能共享內存。在不同應用程序之間交互數據(跨進程通訊),在android
SDK中提供了4種用於跨進程通訊的方式。這4種方式正好對應於android系統中4種應用程序組
件:Activity、Content Provider、Broadcast和Service。其中Activity可以跨進程調用其他應
用程序的Activity;Content Provider可以跨進程訪問其他應用程序中的數據(以Cursor對象形
式返回),當然,也可以對其他應用程序的數據進行增、刪、改操 作;Broadcast可以向
android系統中所有應用程序發送廣播,而需要跨進程通訊的應用程序可以監聽這些廣播;
Service和Content Provider類似,也可以訪問其他應用程序中的數據,但不同的是,Content
Provider返回的是Cursor對象,而Service返回的是Java對象,這種可以跨進程通訊的服務叫
AIDL服務。
『柒』 Android IPC機制
IPC是指兩個進程之間進行數據交互的過程,即:跨進程通信。
進程是一個執行單,在移動設備上指一個程序或者一個應用。一個進程可以有多個線程,也可以只有一個線程,即主線程。在Android里邊,主線程也叫作UI線程,要是在主線程執行大量耗時任務,就會造成界面無法響應,ANR問題,解決這類問題,把耗時操作放在子線程就好。
在Android中,最有特色的進程間通信就是Binder,Binder輕松的實現了進程間的通信。
給四大組件 Activity、Service、Receiver、ContentProvider 在AndroidMenifeist中指定 android:process 屬性,可以指定其運行的進程。
: 開頭的線程是當前應用的私有進程,其它應用不可以和它跑在同一個進程中,而不以 : 開頭的屬於全局進程,其他應用通過ShareUID方式可以和它跑在一個進程中。
Android為了每一個應用(進程)都分配了獨立的虛擬機,不同的虛擬機在內存分配上有不同的地址空間。
多進程會造成如下幾個反面方面的問題:
為了解決這些問題,系統提供了跨進程通信方法,雖然不能直接共享內存,但是可以實現數據共享。Intent來傳遞數據,共享文件,基於Binder的Messenger,ContentProvider,AIDL和Socket。
當我們需要通過Intent和Binder傳輸數據,或者我們需要把對象持久化到存儲設備上,再或者通過網路傳輸給其它客戶端時,Serializable和Parcelable介面可以完成對象的序列化過程。
Serialzable是java提供的序列化介面,是一個空介面,為對象同序列化和反序列化操作。
想讓一個類對象實現序列化,只需要這個類實現Serialzable介面,並聲明一個serialVersionUID即可,serialVersionUID可以聲明成1L或者IDE根據當前類介面自動生成它的hash值。
沒有serialVersionUID不影響序列化,但是可能會影響反序列化。序列化時,系統當前類的serialVersionUID寫入序列化文件中,當反序列化時,回去檢測文件中的serialVersionUID,看它是否和當前類的serialVersionUID一致,如果不一致,無法完成反序列化。
Seriallizable用起來簡單但是開銷大,序列化和反序列過程需要大量的I/O操作,而Parcelable是Android序列化方式,更適合Android平台,效率更高。Parcelable主要用於內存序列化上,而Seriallizable更適用於序列化到本地存儲設備,或者將對象序列化後通過網路傳輸到別的客戶端。
Activity、Service、Receiver都支持在 Intent中傳遞Bundle數據,Bundle實現了Pareclable介面,所以它可以方便地在不同進程間傳輸。
Android基於Linux,使得其並發讀寫文件可以沒有限制的進行,兩個進程可以通過讀寫一個文件來交換數據。共享數據對文件格式沒有要求,雙反約定就行。使用文件共享很有可能出問題。
SharedPreferences是個特例,雖然也是屬於文件的一種,但是由於系統對它的讀寫有一定的緩存策略,即在內存中會有一份SharedPreferences文件的緩存,因此在多進程模式下,系統對他的讀寫變得不可靠,高並發的時候,很大可能會丟失數據。
Messenger可以在不同的進程中傳遞Message對象,在Message中存入我們需要傳遞的數據,就可以實現數據的跨進程傳遞。它是一種輕量級的IPC方案,底層實現是AIDL。
Messenger對AIDL做了封裝,使得我們可以更便捷的實現跨進程通信,它一次只處理一個請求,在服務端不用考慮線程同步問題,在服務端不存在並發執行的情形。實現一個Messenger有如下幾個步驟:
在服務端創建一個Service,同時創建一個Handler,並通過它來創建一個Messenger對象,然後再Service的onBind中返回這個Messenger對象底層Binder即可。
綁定服務端Service,綁定成功後用服務端返回的IBinder對象創建一個Messenger。通過這個對象就可以向服務端發消息了。如果需要服務端回應客戶端,就需要和服務端一樣,創建一個Handler,並通過它來創建一個Messenger對象,然後把這個Messenger對象通過Message的replyTo參數傳給服務端,服務端可以通過這個replyTo參數回應客戶端。
首先要創建一個Service用來監聽客戶端的連接請求,然後創建一個AIDL文件,將暴露給客戶端的介面在這個AIDL文件中聲明,最後在Service中實現AIDL介面即可。
綁定服務端的Service,將服務端返回的Binder對象轉成AIDL介面所屬的類型,接著就可可以範文AIDL里邊的方法了。
在AIDL文件中,並不是所有的額數據類型都是可以使用的。
以上6種數據就是AIDL所支持的所有類型,其中自定義的Parecelable對象和AIDL對象必須顯示的import,不管是否和當前的AIDL文件位於同一個包。
AIDL文件中用到了自定義的Parcelable對象,必須新建一個同名的AIDL文件,在其中聲明它為parcelable類型。
AIDL中除了基礎數據類型,其它類型參數都需要標上方向:in、out、inout,in是輸入型參數,out是輸出型參數,inout是輸入輸出型參數。
上面是遠程服務端示例,AIDL方法在服務端的Binder線程池中執行,因此各個客戶端同時連接的時候,會存在多個線程同時訪問的情形,所以要在AIDL中處理線程同步,這個CopyOnWriteArrayList支持並發的讀寫。
AIDL所支持的是一個抽象的List,只是一個介面,因此雖然服務端返回的是CopyOnWriteArrayList,當時Binder會按照List規范去範文數據並最終形成一個ArrayList傳遞給客戶端。
ServiceConnection 的回調方法在UI線程中運行,服務端的方法有可能很久才能執行完畢,需要考慮ANR的問題。
服務的方法本省就運行再Binder線程池中,本身可以執行大量耗時操作,不要去服務端方法中開縣城去進行非同步任務。
客戶端
服務端
RemoteCallbackList是系統提供專門用於刪除跨進程listener的,它的內部有一個Map結構,用來保存所有的AIDL回調,這個Map的key就是Binder類型,value是CallBack類型。
客戶端解注冊的時候,我們只需要遍歷服務端所有的listener,找出那個和接注冊listener具有相同的Binder對象的服務端listener並把它刪除即可。
RemoteCallbackList的beginBroadcast和finishBroadcast必須配對使用。
ContentProvider是Android專門提供不同應用間進行數據共享的方式。底層實現一樣是Binder。
系統預置了許多ContentProvider,比如通訊錄,日程信息表,只需要通過ContentResolver的query、update、insert、delete方法即可。
『捌』 Android進程間和線程間通信方式
進程:是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。
線程:是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。線程自己基本上不擁有系統資源,只擁有一些在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。
區別:
(1)、一個程序至少有一個進程,一個進程至少有一個線程;
(2)、線程的劃分尺度小於進程,使得多線程程序的並發性高;
(3)、進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,但線程之間沒有單獨的地址空間,一個線程死掉就等於整個進程死掉。
---------------------
一、Android進程間通信方式
1.Bundle
由於Activity,Service,Receiver都是可以通過Intent來攜帶Bundle傳輸數據的,所以我們可以在一個進程中通過Intent將攜帶數據的Bundle發送到另一個進程的組件。
缺點:無法傳輸Bundle不支持的數據類型。
2.ContentProvider
ContentProvider是Android四大組件之一,以表格的方式來儲存數據,提供給外界,即Content Provider可以跨進程訪問其他應用程序中的數據。用法是繼承ContentProvider,實現onCreate,query,update,insert,delete和getType方法,onCreate是負責創建時做一些初始化的工作,增刪查改的方法就是對數據的查詢和修改,getType是返回一個String,表示Uri請求的類型。注冊完後就可以使用ContentResolver去請求指定的Uri。
3.文件
兩個進程可以到同一個文件去交換數據,我們不僅可以保存文本文件,還可以將對象持久化到文件,從另一個文件恢復。要注意的是,當並發讀/寫時可能會出現並發的問題。
4.Broadcast
Broadcast可以向android系統中所有應用程序發送廣播,而需要跨進程通訊的應用程序可以監聽這些廣播。
5.AIDL方式
Service和Content Provider類似,也可以訪問其他應用程序中的數據,Content Provider返回的是Cursor對象,而Service返回的是Java對象,這種可以跨進程通訊的服務叫AIDL服務。
AIDL通過定義服務端暴露的介面,以提供給客戶端來調用,AIDL使伺服器可以並行處理,而Messenger封裝了AIDL之後只能串列運行,所以Messenger一般用作消息傳遞。
6.Messenger
Messenger是基於AIDL實現的,服務端(被動方)提供一個Service來處理客戶端(主動方)連接,維護一個Handler來創建Messenger,在onBind時返回Messenger的binder。
雙方用Messenger來發送數據,用Handler來處理數據。Messenger處理數據依靠Handler,所以是串列的,也就是說,Handler接到多個message時,就要排隊依次處理。
7.Socket
Socket方法是通過網路來進行數據交換,注意的是要在子線程請求,不然會堵塞主線程。客戶端和服務端建立連接之後即可不斷傳輸數據,比較適合實時的數據傳輸
二、Android線程間通信方式
一般說線程間通信主要是指主線程(也叫UI線程)和子線程之間的通信,主要有以下兩種方式:
1.AsyncTask機制
AsyncTask,非同步任務,也就是說在UI線程運行的時候,可以在後台的執行一些非同步的操作;AsyncTask可以很容易且正確地使用UI線程,AsyncTask允許進行後台操作,並在不顯示使用工作線程或Handler機制的情況下,將結果反饋給UI線程。但是AsyncTask只能用於短時間的操作(最多幾秒就應該結束的操作),如果需要長時間運行在後台,就不適合使用AsyncTask了,只能去使用Java提供的其他API來實現。
2.Handler機制
Handler,繼承自Object類,用來發送和處理Message對象或Runnable對象;Handler在創建時會與當前所在的線程的Looper對象相關聯(如果當前線程的Looper為空或不存在,則會拋出異常,此時需要在線程中主動調用Looper.prepare()來創建一個Looper對象)。使用Handler的主要作用就是在後面的過程中發送和處理Message對象和讓其他的線程完成某一個動作(如在工作線程中通過Handler對象發送一個Message對象,讓UI線程進行UI的更新,然後UI線程就會在MessageQueue中得到這個Message對象(取出Message對象是由其相關聯的Looper對象完成的),並作出相應的響應)。
三、Android兩個子線程之間通信
面試的過程中,有些面試官可能會問Android子線程之間的通信方式,由於絕大部分程序員主要關注的是Android主線程和子線程之間的通信,所以這個問題很容易讓人懵逼。
主線程和子線程之間的通信可以通過主線程中的handler把子線程中的message發給主線程中的looper,或者,主線程中的handler通過post向looper中發送一個runnable。但looper默認存在於main線程中,子線程中沒有Looper,該怎麼辦呢?其實原理很簡單,把looper綁定到子線程中,並且創建一個handler。在另一個線程中通過這個handler發送消息,就可以實現子線程之間的通信了。
子線程創建handler的兩種方式:
方式一:給子線程創建Looper對象:
new Thread(new Runnable() {
public void run() {
Looper.prepare(); // 給這個Thread創建Looper對象,一個Thead只有一個Looper對象
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
Looper.loop(); // 不斷遍歷MessageQueue中是否有消息
};
}).start();
---------------------
方式二:獲取主線程的looper,或者說是UI線程的looper:
new Thread(new Runnable() {
public void run() {
Handler handler = new Handler(Looper.getMainLooper()){ // 區別在這!!!
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
};
}).start();
---------------------
『玖』 Android ParcelFileDescriptor實現進程間通信
一個通信通道,實現跨進程的的Socket網路通信。
具體的通信通道的圖如下。
android進程間通信是使用Binder來傳數據,而Binder傳輸的數據,有一個最為基本的要求,就是要實現Parcelable介面。
ParcelFileDescriptor是android提供的一個數據結構。
ParcelFileDescriptor是可以用於進程間Binder通信的FileDescriptor。支持stream 寫入和stream 讀出
我們可以使用
來將PacecelFileDescriptor 與File對應起來,以實現進程間的文件共享。
我們也可以使用
來建立一個pipe通信通道,ParcelFileDescriptor數組第一個元素是read端,第二個元素是write端,通過write端的AutoCloseOutputStream和read端的AutoCloseInputStream,我們就可以實現進程見的數據流傳輸了。
發送端:
1. 業務層調用getOutputStream向通信層發起請求
2. 通信層通過creatPipe 建立一個ParcelFileDescriptor數組,並將write端的pipe[1]返回給業務層
3. 業務層得到pipe[1](ParcelFileDescriptor)後,可以通過AutoCloseOutputStream寫入數據
4. 從通信層的pipe[0]的AutoCloseInputStream中讀出數據通過socket發送出去
接收端:
1. 業務層調用getInputStream向通信層發起請求
2. 通信層通過creatPipe 建立一個ParcelFileDescriptor數組,並將read端的pipe[0]返回給業務層
3. 業務層得到pipe 0 後,可以通過AutoCloseInputStream讀取數據。(如沒有數據,則阻塞,一直等到有數據為止)
4. socket中讀取數據,寫入到通信層的pipe[1]的AutoCloseOutputStream。(pipe[1]一旦寫入,第三步中pipe[2]就可以讀取出數據)