Andorid UNIX SOCKET c代码进程和java代码进程之间通讯

embedded/2024/9/25 19:15:01/

在 Andorid进程间通信之 UNIX SOCKET 一文的实战中,服务端和客户端的代码都是用C语言写的,而Androidd的系统源代码以及APP大多数都是java写的,那么不同的语言写的进程之间,能不能互相通信呢?答案是可以的。本文分为两部分

  • C代码进程做服务端,Android APP做客户端,它们之间相互通信
  • C代码进程做客户端,Android APP做服务端,它们之间相互通信

1,C代码进程做服务端,Android APP做客户端
对于Andorid APP ,做客户端的话,通过LocalSocket来实现。具体代码如下

LocalSocket lsocket = new LocalSocket();
LocalSocketAddress address = new LocalSocketAddress("/dev/server-socket", LocalSocketAddress.Namespace.ABSTRACT);
lsocket.connect(address);

在C代码中,作为客户端的话,会调用 socket和connect 来和服务端建立连接。java代码也是一样的,在connect方法中也是调用socket和connect 来和服务端建立连接。
需要注意的是,address的Namespace默认为ABSTRACT,在调用connect的过程中,对于ABSTRACT,有以下处理

int socket_make_sockaddr_un(const char *name, int namespaceId, struct sockaddr_un *p_addr, socklen_t *alen)
{memset (p_addr, 0, sizeof (*p_addr));size_t namelen;switch (namespaceId) {case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
#if defined(__linux__)namelen  = strlen(name);p_addr->sun_path[0] = 0;//1memcpy(p_addr->sun_path + 1, name, namelen);
#else//省略
#endif//省略p_addr->sun_family = AF_LOCAL;*alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;//2break;  

注释1处,将p_addr的 sun_path[0]设为0 。注释2处因为注释1处的赋值,所以需要对地址的长度进行重新计算。所以在C代码的服务端也需要做对应的修改才行,修改如下:

my_addr.sun_path[0] = 0;	
strcpy(my_addr.sun_path+1, MY_SOCK_PATH);
socklen_t len = sizeof(my_addr.sun_family)+strlen(MY_SOCK_PATH) + 1;
result =  connect(socket_fd,(struct sockaddr*)&my_addr,len);

其它都不用修改,两端就能正常进行通讯了。
java完整代码示例

private void socketmessage() {try {LocalSocket lsocket = new LocalSocket();LocalSocketAddress address = new LocalSocketAddress("/dev/server-socket", LocalSocketAddress.Namespace.ABSTRACT);lsocket.connect(address);String result;/*向服务端写入数据*/BufferedWriter br = new BufferedWriter(new OutputStreamWriter(lsocket.getOutputStream()));br.write("client say hello!");br.newLine();br.flush();/*读取数据*/InputStream inputStream = lsocket.getInputStream();byte[] buf = new byte[inputStream.available() -1];inputStream.read(buf,0,inputStream.available() -1) ;String str =new String(buf);Log.d("test","str:"+str);lsocket.close();} catch (IOException e) {e.printStackTrace();}}

C代码参考文头提的那篇文章即可,只需记得做上面对地址处理的修改。

2,C代码进程做客户端,Android APP做服务端
同理,C代码做客户端的话,在绑定的时候也仅仅需要对地址额外的处理一下就行了,代码如下:

my_addr.sun_path[0] = 0;
strcpy(my_addr.sun_path+1, MY_SOCK_PATH);
socklen_t len = sizeof(my_addr.sun_family)+strlen(MY_SOCK_PATH) + 1;
unlink(MY_SOCK_PATH);
result = bind(listenfd,(struct sockaddr *)&my_addr,len);

这里重点说一下java做服务端,是如何实现的。参考Zygote
做服务端的话,通过LocalServerSocket来实现。第一步就是创建一个LocalServerSocket对象

registerZygoteSocket("/dev/server-socket");private  void registerZygoteSocket(String socketName) {if (sServerSocket == null) {try {sServerSocket = new LocalServerSocket(socketName);} catch (IOException e) {e.printStackTrace();}}}

在新建一个LocalServerSocket对象时,会依次调用socket,bind,listen 来创建socket并监听服务端连接的请求。

第二部就是进入循环,在循环中等待客户端请求连接。在循环中使用epoll机制。连接了就可以和客户端相互通信了

private void runSelectLoop(){ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();ArrayList<LocalSocketClass> peers = new ArrayList<LocalSocketClass>();peers.add(null);//占一个位置fds.add(sServerSocket.getFileDescriptor());while (true){StructPollfd[] pollFds = new StructPollfd[fds.size()];for (int i = 0; i < pollFds.length; ++i) {pollFds[i] = new StructPollfd();pollFds[i].fd = fds.get(i);pollFds[i].events = (short) POLLIN;}try {Os.poll(pollFds, -1);} catch (ErrnoException e) {e.printStackTrace();}for (int i = pollFds.length - 1; i >= 0; --i) {if ((pollFds[i].revents & POLLIN) == 0) {continue;}if (i == 0) {//有客户端建立连接,因为fds数组中第一个元素是服务端的socket fdtry {LocalSocket localSocket = sServerSocket.accept();LocalSocketClass localSocketClass = new LocalSocketClass(localSocket);peers.add(localSocketClass);fds.add(localSocket.getFileDescriptor());} catch (IOException e) {e.printStackTrace();}} else {//客户端有数据来了(其它的fd都是通过accept得到的客户端的fd)boolean done = peers.get(i).runOnce();if (done) {peers.remove(i);fds.remove(i);}}}}}

runOnce中就是对数据的处理

public boolean runOnce(){/*读取客户端数据*/try {BufferedReader mSocketReader = new BufferedReader(new InputStreamReader(localSocket.getInputStream()), 256);String s = mSocketReader.readLine();Log.d("test", "runOnce: "+s);/*向服务端写入数据*/BufferedWriter br = new BufferedWriter(new OutputStreamWriter(localSocket.getOutputStream()));br.write(s);br.newLine();br.flush();}catch (Exception e){e.printStackTrace();}return false;}

总结
对于UNIX SOCKET ,C代码和Java代码之间是可以相互通信的,并且可以相互作为客户端和服务端通信。有一点需要注意的是:两端对于地址的处理一定要保持一致,否则两端连接不了。


http://www.ppmy.cn/embedded/15447.html

相关文章

数据结构-枚举算法

枚举算法 理解枚举思想 枚举算法的核心思想是系统地列举并检查所有可能的候选解&#xff0c;以确定哪些解满足给定问题的条件。穷举所有可能性:枚举算法的基本思路是穷举问题的解空间&#xff0c;即一一列举所有可能的解状态或解配置。这通常涉及到对问题参数、变量取值、对象组…

【前端】3. CSS【万字长文】

CSS 是什么 层叠样式表 (Cascading Style Sheets). CSS 能够对网页中元素位置的排版进行像素级精确控制, 实现美化页面的效果. 能够做到页面的样式和结构分离. CSS 就是 “东方四大邪术” 之化妆术. 基本语法规范 选择器 {一条/N条声明} 选择器决定针对谁修改 (找谁)声明决…

冰蝎、蚁剑和哥斯拉

冰蝎、蚁剑和哥斯拉都是常见的远程管理工具&#xff0c;它们的原理是通过在受害者主机上部署后门程序&#xff0c;通过远程控制的方式进行攻击。然而&#xff0c;它们在功能上存在一些差异。 冰蝎主要通过Java Web服务器实现远程控制。攻击者首先在受害者机器上植入后门&#x…

基于YOLOv8+Pyqt5火焰烟雾检测系统

1、YOLOv8的基本原理 YOLOv8是一种前沿的目标检测技术&#xff0c;它基于先前YOLO版本在目标检测任务上的成功&#xff0c;进一步提升了性能和灵活性。主要的创新点包括一个新的骨干网络、一个新的 Ancher-Free 检测头和一个新的损失函数&#xff0c;可以在从 CPU 到 GPU 的各…

HarmonyOS开发 - hilog日志系统

文章目录 一、介绍二、对日志的封装 一、介绍 harmony OS提供了系统日志打印 hilog开发者可以通过使用这些接口实现日志相关功能&#xff0c;输出日志时可以指定日志类型、所属业务领域、日志TAG标识、日志级别等。系统文档HiLog日志打印 二、对日志的封装 代码 import hil…

Android AIDL传递类对象

Android 使用AIDL来进行跨进程通讯时&#xff0c;除了传递基本数据类型之外&#xff0c;还可以传递类对象&#xff0c;值得注意的是该类必须实现Parcelable接口。具体实现方案如下&#xff08;本文居于已经了解并可以实现使用bindService来进行跨进程通讯&#xff09; server端…

Jenkins CI/CD 持续集成专题三 Jenkins 使用shell脚本打包组件配置流程

第一步 新建任务 第二步 输入项目名称和选择自由风格的软件项目点击确定 第三步 配置下项目地址和账号密码 第四步 配置 build steps 选择 shell 脚本 第五步 shell 配置 &#xff08;注意shell 必须以#!/bin/sh开头&#xff0c;否则会报 找不到shell 命令的错&#xff09; …

解决Jmeter 4.x 请求到elasticsearch 中文乱码的问题

文章目录 前言解决Jmeter 4.x 请求到elasticsearch 中文乱码的问题 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差&#xff0c;实在白嫖的话&#…