Android ParcelFileDescriptor实现进程间通信

需求

一个通信通道,实现跨进程的的Socket网络通信。
具体的通信通道的图如下。

需求分析
  1. 我们需要一个进程一直做通信通道的事情,业务进程把数据通过进程间通信交给通信进程。
  2. 通信进程通过Socket通道将数据发给网络另外一端的通信进程。
  3. 接收端的通信进程把数据再交给业务进程。
android进程间通信基本方式

android进程间通信是使用Binder来传数据,而Binder传输的数据,有一个最为基本的要求,就是要实现Parcelable接口。

ParcelFileDescriptor

ParcelFileDescriptor是android提供的一个数据结构。

文件描述符,是一种程序读写已打开文件、socket的对象。

FileDescriptor对象,它代表了原始的Linux文件描述符
ParcelFileDescriptor对象,是原始文件描述符的一个复制,对象跟fd不同,但都是操作同一个底层文件流以及文件位置指针

public class ParcelFileDescriptor 
extends Object implements Parcelable, Closeable

ParcelFileDescriptor是可以用于进程间Binder通信的FileDescriptor。支持stream 写入和stream 读出

public static class ParcelFileDescriptor.AutoCloseInputStream 
extends FileInputStream 

public static class ParcelFileDescriptor.AutoCloseOutputStream 
extends FileOutputStream 

我们可以使用

ParcelFileDescriptor open (File file, int mode)

来将PacecelFileDescriptor 与File对应起来,以实现进程间的文件共享。

我们也可以使用

ParcelFileDescriptor[] createPipe ()

来建立一个pipe通信通道,ParcelFileDescriptor数组第一个元素是read端,第二个元素是write端,通过write端的AutoCloseOutputStream和read端的AutoCloseInputStream,我们就可以实现进程见的数据流传输了。

完整的跨进程数据传输方案如下:
  1. 文件传输

    两端业务层都把Uri对应的ParcelFileDescriptor发送给通信层,发送端通信层从AutoCloseInputStream中取数据发送,接收端通信层获取到数据后,写入到AutoCloseOutputStream中。

  2. 流传输

发送端:
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. 业务层得到pipe0后,可以通过AutoCloseInputStream读取数据。(如没有数据,则阻塞,一直等到有数据为止)
4. socket中读取数据,写入到通信层的pipe[1]的AutoCloseOutputStream。(pipe[1]一旦写入,第三步中pipe[2]就可以读取出数据)

简单的ParcelFileDescriptor使用——pipe

public class DemoParcefliledescriptor extends AppCompatActivity {
 
    private static final String TAG = "DemoPFD";
 
    private static final String[] PERMISSIONS = {
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
    };
    private static final int PERMISSIONS_CODE = 3006;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo_null);
 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(PERMISSIONS, PERMISSIONS_CODE);
        }
 
        FileOutputStream outputStream = new FileOutputStream(getStreamFd());
        try {
            outputStream.write(99);
            outputStream.write(98);
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
 
    private FileDescriptor getStreamFd() {
        ParcelFileDescriptor[] pipes = null;
 
        try {
            pipes = ParcelFileDescriptor.createPipe();
            new TransferThread(new ParcelFileDescriptor.AutoCloseInputStream(pipes[0])).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
 
        return pipes[1].getFileDescriptor();
    }
 
    static class TransferThread extends Thread {
        InputStream in;
        FileOutputStream out;
 
        TransferThread(InputStream in, FileOutputStream out) {
            this.in = in;
            this.out = out;
        }
 
        TransferThread(InputStream in) {
            this.in = in;
 
            File outFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/zlq_pdf");
            Log.i(TAG, "File: " + outFile.getAbsolutePath());
 
            try {
                out = new FileOutputStream(outFile);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
 
        @Override
        public void run() {
            byte[] buf = new byte[1024*2];
 
            int len;
            try {
                while((len=in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                    Log.i(TAG, "out:" + len);
 
                }
 
                in.close();
                out.flush();
                out.getFD().sync();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/544490.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RedisTemplate

3.3.RedisTemplate 在Sentinel集群监管下的Redis主从集群,其节点会因为自动故障转移而发生变化,Redis的客户端必须感知这种变化,及时更新连接信息。Spring的RedisTemplate底层利用lettuce实现了节点的感知和自动切换。 下面,我们…

家庭网络防御系统搭建-虚拟机安装siem/securityonion网络连接问题汇总

由于我是在虚拟机中安装的security onion,在此过程中,遇到很多的网络访问不通的问题,通过该文章把网络连接问题做一下梳理。如果直接把securityonion 安装在物理机上,网络问题则会少很多。 NAT无法访问虚拟机 security onion虚拟…

ssm051网上医院预约挂号系统+jsp

网上医院预约挂号系统设计与实现 摘 要 如今的信息时代,对信息的共享性,信息的流通性有着较高要求,因此传统管理方式就不适合。为了让医院预约挂号信息的管理模式进行升级,也为了更好的维护医院预约挂号信息,网上医院…

dbeaver数据库语言编辑器设置jdbc驱动

打开 dbeaver 软件 数据库 -> 驱动管理器 以mysql为例 双击 MySQL -> 库 -> 添加工件 然后 打开maven组件库 官网 找到mysql驱动对应的maven工件地址 复制进去然后确认就行了 参考 大神博客

<计算机网络自顶向下> TCPUDP套接字编程

应用实现:源端的应用进程交换报文实现应用协议,来实现各种各样的网络应用(dash,email, etc) 而应用层通信不可以直接通信,需要借助下层的服务才可以进行,通过层间接口交给下层,通过…

Hadoop概述及集群搭建

文章目录 一、Hadoop介绍二、Hadoop发展简史三、Hadoop核心组件四、Hadoop架构变迁1、Hadoop 1.02、Hadoop 2.03、Hadoop 3.0 五、Hadoop集群简介六、Hadoop部署模式七、Hadoop 集群搭建第一步:创建虚拟机第二步:安装Linux镜像第三步:网络配置…

Go微服务: go-micro集成consul的注册中心和配置中心

微服务与注册中心的关系图 这个图很好说明了微服务之间的关系,以及consul注册中心的重要性 环境准备 1 )consul 集群 假设consul 集群已经搭建,已有5台server和2台client这里2台client被nginx做负载均衡,假设最终本地的访问地址…

了解 Vue 工程化开发中的组件通信

目录 1. 组件通信语法 1.1. 什么是组件通信? 1.2. 为什么要使用组件通信? 1.3. 组件之间有哪些关系(组件关系分类)? 1.4. 组件通信方案有哪几类 ? 2. 父子通信流程图 3. 父传子 3.1. 父传子核心流程…

1. 信息存储

系列文章目录 信息的表示和处理 : Information Storage(信息存储)Integer Representation(整数表示)Integer Arithmetic(整数运算)Floating Point(浮点数) 文章目录 系列文章目录前…

网络网络层之(2)ARP协议

网络网络层之(2)ARP协议 Author:Once Day Date: 2024年4月1日 漫漫长路,有人对你笑过嘛… 全系列文档可参考专栏:通信网络技术_Once-Day的博客-CSDN博客。 参考文档: 《TCP/IP详解卷一》arp(8) - Linux manual page (man7.org)彻底搞懂系…

专业照片编辑软件ON1 Photo RAW 2024 mac/win

ON1 Photo RAW 2024 for Mac是一款集专业性与易用性于一体的照片编辑软件。它拥有简洁直观的用户界面,即便对于摄影新手,也能快速上手。软件支持RAW格式照片处理,能够完整保留照片原始信息,让后期调整更加灵活。 在功能方面&#…

利用Sentinel解决雪崩问题(一)流量控制

1、解决雪崩问题的常见方式有四种: 超时处理:设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止等待;舱壁模式:限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离;熔断降级:由断路器统计业务…

Textarea的常用属性thymeleaf

文章目录 textareathymeleaf1.基础使用2.代码块的切换3.链接表达式1)范例 4.前后端5.遍历1.th:each2.th:switch3.添加属性 组件替换 每周总结 textarea -webkit-scrollbar:width:0;让滚动条隐藏,宽度为0 resize&#x…

浦大喜奔APP8.0智能升级,发力数字金融深化五大金融篇章服务

1. 浦大喜奔立足科技赋能持续迭代升级,筑牢用户体验护城河 浦发信用卡中心坚持数字科技与客户体验双轮驱动,以科技赋能发展,优化整体系统性能,全方位支撑浦大喜奔 APP提高线上客户服务能力与体验,积极服务民生消费&a…

【MATLAB源码-第188期】基于matlab的64QAM系统相位偏移估计EOS算法仿真,对比补偿前后的星座图误码率。

操作环境: MATLAB 2022a 1、算法描述 1. 引言 M-QAM调制技术的重要性 现代通信系统追求的是更高的数据传输速率和更有效的频谱利用率。M-QAM调制技术,作为一种高效的调制方案,能够通过在相同的带宽条件下传输更多的数据位来满足这一需求…

大模型面试准备(十八):使用 Pytorch 从零实现 Transformer 模型

节前,我们组织了一场算法岗技术&面试讨论会,邀请了一些互联网大厂朋友、参加社招和校招面试的同学,针对大模型技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何备战、面试常考点分享等热门话题进行了深入的讨论。 合集在这…

Kafka 架构深入探索

目录 一、Kafka 工作流程及文件存储机制 二、数据可靠性保证 三 、数据一致性问题 3.1follower 故障 3.2leader 故障 四、ack 应答机制 五、部署FilebeatKafkaELK 5.1环境准备 5.2部署ELK 5.2.1部署 Elasticsearch 软件 5.2.1.1修改elasticsearch主配置文件 5.2…

MacOS Docker 部署 Solr 搜索引擎

一、简介 Solr 是 Apache 下的一个顶级开源项目,采用 Java 开发,它是基于 Lucene 的全文搜索服务器。Solr 可以独立运行在 Jetty、Tomcat 等这些 Servlet 容器中。Solr 提供了比 Lucene 更为丰富的查询语言,同时实现了可配置、可扩展&#x…

Kafka 简单介绍

目录 一 消息队列(MQ) 1,为什么需要消息队列(MQ 2,常见的 MQ 中间件 3,MQ 传统应用场景之异步处理 4,使用消息队列的好处 5,消息队列的两种模式 5.1点对点模式&#xf…

Spring Bean的生命周期总结(包含面试题)

目录 一、Bean的初始化过程 1. 加载Spring Bean 2. 解析Bean的定义 3. Bean属性定义 4. BeanFactoryPostProcessor 扩展接口 5. 实例化Bean对象 6. Aware感知 7. 初始化方法 8. 后置处理 9. destroy 销毁 二、Bean的单例与多例模式 2.1 单例模式(Sin…