安卓IPC機制之LocalSocket

LocalSocket作為安卓提供的一種IPC機制,可能應(yīng)用層的同學比較陌生,我實際也是在這段時間做項目使用到才注意到它并去了解的。不過實際上framework層里面被頻繁使用到了,例如我很久前寫的博客從源碼看安卓應(yīng)用的啟動過程里面提到其他進程和Zygote進程之間的通信使用的是LocalSocket。

那么LocalSocket和Socket到底有什么不同呢?官方文檔里面其實提到了它其實是基于UNIX-domain socket的:

Non-standard class for creating an inbound UNIX-domain socket in the Linux abstract namespace.

Socket本來是用來做不同主機間的網(wǎng)絡(luò)通信的,如果有人想拿來做本機的IPC通信就會發(fā)現(xiàn)它的性能堪憂(例如實現(xiàn)binder機制做不到的傳輸大文件),因為它需要走網(wǎng)絡(luò)協(xié)議棧、打包拆包、計算校驗等,如果是TCP還需要走三次握手和應(yīng)答。

于是后面就發(fā)展出了UNIX-domain socket (LocalSocket),它的api和socket的基本一致,但是本質(zhì)上只是一種IPC通信,不可和外部主機通信,但是因為IPC通信是可靠通信,直接將數(shù)據(jù)拷貝到目標進程內(nèi)存即可,所以沒有之前說的那些耗時的操作。

使用方式

我們先來看看它的使用方式:

private void demoClient() throws IOException {
    LocalSocket client = new LocalSocket();
    client.connect(new LocalSocketAddress("me.linjw.localsocket"));
    client.getOutputStream().write(123);
    int read = client.getInputStream().read();
    Log.d(TAG, "response from server : " + read);
    client.close();
}

private void demoServer() throws IOException {
    LocalServerSocket server = new LocalServerSocket("me.linjw.localsocket");
    LocalSocket client = server.accept();
    int read = client.getInputStream().read();
    Log.d(TAG, "request from client :" + read);
    client.getOutputStream().write(read + 1);
    client.getOutputStream().flush();
    client.close();
}

// 打印
// request from client :123
// response from server : 124

沒錯,看起來和普通Socket的用法很類似了。

性能

性能是評判一種ipc進制好壞的重要指標,例如我們常用的Binder機制就是用了mmap機制實現(xiàn)了數(shù)據(jù)的一次拷貝提高了傳輸速度。

于是我寫了一個測試程序來對比AIDL、LocalSocket和TCP Socket的傳輸速度。測試的邏輯大概是:

  1. 每次傳輸讀或者寫1024 byte數(shù)據(jù)
  2. 計算3000次讀或者寫的耗時(也就是計算讀3000k或者寫3000k數(shù)據(jù)的總耗時)
  3. LocalSocket和TCP Socket每次傳輸完數(shù)據(jù)都斷開連接,下次需要重新連接

在我們的產(chǎn)品設(shè)備上得到的實際數(shù)據(jù)如下:

方式 方向 第一次3000k 第二次3000k 第三次3000k 第四次3000k 平均時間
AIDL 1.711s 1.195s 1.25s 1.169s 1.33125s
LocalSocket 1.674s 1.286s 1.185s 1.219s 1.341s
TCP Socket 10.188s 8.926s 8.865s 8.803s 9.1955s
AIDL 1.261s 1.212s 1.175s 1.23s 1.2195s
LocalSocket 1.387s 1.323s 1.23s 1.35s 1.3225s
TCP Socket 8.284s 8.242s 8.324s 8.285s 8.28375s

從上面的數(shù)據(jù)可以看出來LocalSocket雖然會比AIDL慢但是也差的不多,而tcp的耗時就比較多了。雖然我沒有具體看過LocalSocket的底層原理,但是想來既然它在framework層被頻繁使用,那么谷歌應(yīng)該也應(yīng)該會考慮到性能這一點。

優(yōu)缺點

優(yōu)點:

  1. 可以進行數(shù)據(jù)流讀寫,沒有大小限制
  2. 比TCP Socket會更加安全,因為不能通過抓包監(jiān)聽傳輸?shù)臄?shù)據(jù)
  3. 不會開啟線程池(Zygote之所以使用它而不是Binder也是因為Binder機制默認會啟動線程池,而fork在多線程下只會fork出當前線程)

缺點:

  1. 比Binder的速度還是會稍微慢那么一點點
  2. 沒有像AIDL這樣的高層封裝,需要自己實現(xiàn)
  3. 和TCP Socket對比起來不能跨主機通信

需要注意的地方

  1. 雖然不是真正的網(wǎng)絡(luò)傳輸,但是也需要聲明android.permission.INTERNET權(quán)限,要不然同樣會報java.net.SocketException: Permission denied異常
  2. 雖然可以通過LocalSocket和framework層直接通信,但是如果系統(tǒng)打開了SeLinux就會出現(xiàn)Permission denied異常
  3. 在模擬器上LocalSocket的flush用多了耗時有時候會比較嚴重(Tcp沒有問題,實機測試LocalSocket也沒有出現(xiàn)問題,猜測和系統(tǒng)相關(guān))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容