android socket双向,Android中socketpair双向通信详解

本文详细探讨了Android中进程间通信(IPC)的概念,特别关注了Socketpair和Binder两种方法。Socketpair用于线程间和有亲缘关系进程间的通信,而Binder则适用于APP间的通信,但非双向。通过实例展示了如何使用Socketpair实现实时双向通信,以及如何借助Binder传递文件句柄实现跨APP进程通信。
摘要由CSDN通过智能技术生成

Android很多地方会涉及到进程间的通信,比如输入系统,那么进程间通信会涉及哪些内容呢?

1、进程:负责读取和分发事件

2、应用程序:负责处理输入事件

上面这两个进程会涉及哪些双向通信呢:

1.进程会发送输入事件

2.应用程序会告知事件处理完或APP已关闭

这里大家可能会有疑惑,binder系统能否实现上面所说的双向通信呢?

答案是不行,binder分为server和client,每次都由client主动发出请求,server收到请求后进行答复,这样的缺点就是每次请求只能单方发起,server不能主动发送数据给client,这样自然不能称为双向通信。

所以这里引入一个新的方法,叫“socketpair”

APP通过socketpair调用得到两个文件句柄,假设这两个文件句柄是fd1和fd2,这两个文件都对应有两个缓冲区(send_buf、rcv_buf),当某个进程或线程通过fd1写到他的send_buf的时候,内核里面的socket就会把send_buf里面的数据写到fd2的rcv_buf里面,另外一个线程或进程就可以读取fd2得到那些数据了,相反同理。

但是它也有缺点:由于是通过创建文件句柄来访问句柄实现的通信,那么谁可以看到这个句柄呢,只有当前APP创建出来的线程或它创建出来的子进程才能看到这些文件句柄,所以只适用于线程间通信,或者具有亲缘关系(父子进程)的进程间通信。

那么如果想使用socketpair来实现任意间的进程间的双向通信怎么办?

假设现在有APP1和APP2,这两个APP想进行任意间的进程通信,那么APP2需要得到APP1的fd2才行,怎么得到呢?可以通过binder通信,把fd2传给APP2,当然在APP2里面它就变为fd3了,这样这个任意的进程APP2就可以通过socketpair来进行通信了。这篇暂不讲解binder的实现方式

下面讲解一下“Socketpair”的程序及使用:

#include

#include

#include

#include /* See NOTES */

#include

#define SOCKET_BUFFER_SIZE (32768U)

/* 参考:

* frameworks\native\libs\input\InputTransport.cpp

*/

/* 线程1函数实现 */

void *function_thread1 (void *arg)

{

int fd = (int)arg;/* 把文件句柄转换出来 */

char buf[500];

int len;

int cnt = 0;

while (1)

{

/* 向 main线程发出: Hello, main thread */

len = sprintf(buf, "Hello, main thread, cnt = %d", cnt++);

write(fd, buf, len);

/* 读取数据(main线程发回的数据) */

len = read(fd, buf, 500);

buf[len] = '\0';

printf("%s\n", buf);

/* 延时5秒钟 */

sleep(5);

}

return NULL;

}

int main(int argc, char **argv)

{

int sockets[2];

/* 使用 socketpair 得到两个文件句柄到数组sockets */

socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets);

/* 设置缓冲区, 每个文件句柄对应两个缓冲区,两个文件对应四个 */

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));

/* 创建线程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];/* 当前main函数的文件句柄是sockets[0] */

while(1)

{

/* 读数据: 读线程1发出的数据 */

len = read(fd, buf, 500);

buf[len] = '\0';

printf("%s\n", buf);

/* main thread向thread1 发出: Hello, thread1 */

len = sprintf(buf, "Hello, thread1, cnt = %d", cnt++);

write(fd, buf, len);

}

}

程序非常简单,先是使用socketpair得到两个文件句柄并设置发送接收缓冲区,然后创建另一个线程,在线程中通过文件句柄读写数据到main线程中,mian也执行同样的操作实现双向通信。

测试验证:

90a3c0fec05832e3a9834e584ef8fd72.png

检查是否存在这两个线程:

c4521558fcc71ab783b803f71f3224b8.png

我们还可以修改程序,让应用程序fork出一个子进程,然后让父子进程通过socketpair来实现双向通信,比较简单,这里就不细讲了。

由于socekpair只适用于线程间通信,或者具有亲缘关系,如果想实现任意的两个进程间的双向通信就需要使用binder系统把fd传给另一个进程,这里简单说下过程,如下:

使用binder传输文件句柄:

假设APP1,open某个文件句柄得到fd1

通过binder驱动根据fd1得到file结构体,即files->fdt->fd[fd1]

从APP2的files->fdt->fd中取出一个空项,假设是fd2,让fd2指向fd1的file结构体,即files->fdt->fd[fd2]=file

之后APP1可以通过fd1,APP2可以通过fd2访问同一个文件了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值