Android中socketpair雙向通信詳解
Android很多地方會(huì)涉及到進(jìn)程間的通信,比如輸入系統(tǒng),那么進(jìn)程間通信會(huì)涉及哪些內(nèi)容呢?
1、進(jìn)程:負(fù)責(zé)讀取和分發(fā)事件
2、應(yīng)用程序:負(fù)責(zé)處理輸入事件
上面這兩個(gè)進(jìn)程會(huì)涉及哪些雙向通信呢:
1.進(jìn)程會(huì)發(fā)送輸入事件
2.應(yīng)用程序會(huì)告知事件處理完或APP已關(guān)閉
這里大家可能會(huì)有疑惑,binder系統(tǒng)能否實(shí)現(xiàn)上面所說(shuō)的雙向通信呢?
答案是不行,binder分為server和client,每次都由client主動(dòng)發(fā)出請(qǐng)求,server收到請(qǐng)求后進(jìn)行答復(fù),這樣的缺點(diǎn)就是每次請(qǐng)求只能單方發(fā)起,server不能主動(dòng)發(fā)送數(shù)據(jù)給client,這樣自然不能稱(chēng)為雙向通信。
所以這里引入一個(gè)新的方法,叫“socketpair”
APP通過(guò)socketpair調(diào)用得到兩個(gè)文件句柄,假設(shè)這兩個(gè)文件句柄是fd1和fd2,這兩個(gè)文件都對(duì)應(yīng)有兩個(gè)緩沖區(qū)(send_buf、rcv_buf),當(dāng)某個(gè)進(jìn)程或線程通過(guò)fd1寫(xiě)到他的send_buf的時(shí)候,內(nèi)核里面的socket就會(huì)把send_buf里面的數(shù)據(jù)寫(xiě)到fd2的rcv_buf里面,另外一個(gè)線程或進(jìn)程就可以讀取fd2得到那些數(shù)據(jù)了,相反同理。
但是它也有缺點(diǎn):由于是通過(guò)創(chuàng)建文件句柄來(lái)訪問(wèn)句柄實(shí)現(xiàn)的通信,那么誰(shuí)可以看到這個(gè)句柄呢,只有當(dāng)前APP創(chuàng)建出來(lái)的線程或它創(chuàng)建出來(lái)的子進(jìn)程才能看到這些文件句柄,所以只適用于線程間通信,或者具有親緣關(guān)系(父子進(jìn)程)的進(jìn)程間通信。
那么如果想使用socketpair來(lái)實(shí)現(xiàn)任意間的進(jìn)程間的雙向通信怎么辦?
假設(shè)現(xiàn)在有APP1和APP2,這兩個(gè)APP想進(jìn)行任意間的進(jìn)程通信,那么APP2需要得到APP1的fd2才行,怎么得到呢?可以通過(guò)binder通信,把fd2傳給APP2,當(dāng)然在APP2里面它就變?yōu)閒d3了,這樣這個(gè)任意的進(jìn)程APP2就可以通過(guò)socketpair來(lái)進(jìn)行通信了。這篇暫不講解binder的實(shí)現(xiàn)方式
下面講解一下“Socketpair”的程序及使用:
#include <pthread.h> #include <unistd.h> #include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #define SOCKET_BUFFER_SIZE (32768U) /* 參考: * frameworks\native\libs\input\InputTransport.cpp */ /* 線程1函數(shù)實(shí)現(xiàn) */ void *function_thread1 (void *arg) { int fd = (int)arg;/* 把文件句柄轉(zhuǎn)換出來(lái) */ char buf[500]; int len; int cnt = 0; while (1) { /* 向 main線程發(fā)出: Hello, main thread */ len = sprintf(buf, "Hello, main thread, cnt = %d", cnt++); write(fd, buf, len); /* 讀取數(shù)據(jù)(main線程發(fā)回的數(shù)據(jù)) */ len = read(fd, buf, 500); buf[len] = '\0'; printf("%s\n", buf); /* 延時(shí)5秒鐘 */ sleep(5); } return NULL; } int main(int argc, char **argv) { int sockets[2]; /* 使用 socketpair 得到兩個(gè)文件句柄到數(shù)組sockets */ socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets); /* 設(shè)置緩沖區(qū), 每個(gè)文件句柄對(duì)應(yīng)兩個(gè)緩沖區(qū),兩個(gè)文件對(duì)應(yīng)四個(gè) */ int bufferSize = SOCKET_BUFFER_SIZE; setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); /* 創(chuàng)建線程1(thread1),并把文件句柄sockets[1]傳給子線程thread1 */ pthread_t threadID; pthread_create(&threadID, NULL, function_thread1, (void *)sockets[1]); char buf[500]; int len; int cnt = 0; int fd = sockets[0];/* 當(dāng)前main函數(shù)的文件句柄是sockets[0] */ while(1) { /* 讀數(shù)據(jù): 讀線程1發(fā)出的數(shù)據(jù) */ len = read(fd, buf, 500); buf[len] = '\0'; printf("%s\n", buf); /* main thread向thread1 發(fā)出: Hello, thread1 */ len = sprintf(buf, "Hello, thread1, cnt = %d", cnt++); write(fd, buf, len); } }
程序非常簡(jiǎn)單,先是使用socketpair得到兩個(gè)文件句柄并設(shè)置發(fā)送接收緩沖區(qū),然后創(chuàng)建另一個(gè)線程,在線程中通過(guò)文件句柄讀寫(xiě)數(shù)據(jù)到main線程中,mian也執(zhí)行同樣的操作實(shí)現(xiàn)雙向通信。
測(cè)試驗(yàn)證:
檢查是否存在這兩個(gè)線程:
我們還可以修改程序,讓?xiě)?yīng)用程序fork出一個(gè)子進(jìn)程,然后讓父子進(jìn)程通過(guò)socketpair來(lái)實(shí)現(xiàn)雙向通信,比較簡(jiǎn)單,這里就不細(xì)講了。
由于socekpair只適用于線程間通信,或者具有親緣關(guān)系,如果想實(shí)現(xiàn)任意的兩個(gè)進(jìn)程間的雙向通信就需要使用binder系統(tǒng)把fd傳給另一個(gè)進(jìn)程,這里簡(jiǎn)單說(shuō)下過(guò)程,如下:
使用binder傳輸文件句柄:
- 假設(shè)APP1,open某個(gè)文件句柄得到fd1
- 通過(guò)binder驅(qū)動(dòng)根據(jù)fd1得到file結(jié)構(gòu)體,即files->fdt->fd[fd1]
- 從APP2的files->fdt->fd中取出一個(gè)空項(xiàng),假設(shè)是fd2,讓fd2指向fd1的file結(jié)構(gòu)體,即files->fdt->fd[fd2]=file
- 之后APP1可以通過(guò)fd1,APP2可以通過(guò)fd2訪問(wèn)同一個(gè)文件了
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android中點(diǎn)擊隱藏軟鍵盤(pán)最佳方法
本文介紹了Android中點(diǎn)擊隱藏軟鍵盤(pán)最佳方法。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-01-01Android編程實(shí)現(xiàn)點(diǎn)擊鏈接打開(kāi)APP功能示例
這篇文章主要介紹了Android編程實(shí)現(xiàn)點(diǎn)擊鏈接打開(kāi)APP功能,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android實(shí)現(xiàn)點(diǎn)擊鏈接打開(kāi)APP功能的具體步驟與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-01-01Android購(gòu)物車(chē)項(xiàng)目快速開(kāi)發(fā)
這篇文章主要為大家詳細(xì)介紹了Android購(gòu)物車(chē)項(xiàng)目快速開(kāi)發(fā),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01使用Flutter開(kāi)發(fā)的抖音國(guó)際版實(shí)例代碼詳解
這篇文章主要介紹了使用Flutter開(kāi)發(fā)的抖音國(guó)際版,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05Android編程實(shí)現(xiàn)創(chuàng)建,刪除,判斷快捷方式的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)創(chuàng)建,刪除,判斷快捷方式的方法,結(jié)合實(shí)例形式分析了Android編程針對(duì)快捷方式的常用操作技巧,需要的朋友可以參考下2017-02-02