Android是建立在Linux之上的OS,在涉及到安全、网络协议、文件加密等功能时,往往需要通过C语言调用底层API来实现,而如何发出指令让C端执行我们想要的功能,并且在执行之后有返回结果呢,这就需要打通Java端进程和C端进程,使之能高效地通信。这样,C端进程用于实现功能,Java端进程负责UI、功能的触发及结果处理就可以了。

  对于*nix系统来说,“一切皆为文件”,Socket也不例外,Socket按照收发双方的媒介来说有三种类型:1,通过网络端口;2,通过文件系统;3,通过内存映射文件。具体说来,三种类型均可以用来作为IPC的Socket:1,通过本地回环接口(即LoopBack)127.0.0.1来收发数据;2,通过文件作为收发数据的中转站;3,在内存中开辟一块区域作为收发数据的中转站,此区域仍然使用文件读写API进行访问。LocalSocket支持方式2和方式3,从效率的角度来说,显然是方式3效率最高,那么下面我们就使用LocalSocket来演示如何实现Java端进程与C端进程之间的IPC。

  以下的demo是Java端作为server,C端作为client;实际场景中可能更多的是Java端作为client,而C端作为server。

服务端代码如下:

 package main.activity;

 import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader; import android.app.Activity;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.os.Bundle;
import android.util.Log; /**
* @author pengyiming
* @note 启动localSocketServer
*
*/ public class LocalSocketServerActivity extends Activity
{
/* 数据段begin */
private final String TAG = "server"; private ServerSocketThread mServerSocketThread;
/* 数据段end */ /* 函数段begin */
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState); mServerSocketThread = new ServerSocketThread();
mServerSocketThread.start();
} @Override
protected void onDestroy()
{
super.onDestroy(); mServerSocketThread.stopRun();
}
/* 函数段end */ /* 内部类begin */
private class ServerSocketThread extends Thread
{
private boolean keepRunning = true;
private LocalServerSocket serverSocket; private void stopRun()
{
keepRunning = false;
} @Override
public void run()
{
try
{
serverSocket = new LocalServerSocket("pym_local_socket");
}
catch (IOException e)
{
e.printStackTrace(); keepRunning = false;
} while(keepRunning)
{
Log.d(TAG, "wait for new client coming !"); try
{
LocalSocket interactClientSocket = serverSocket.accept(); //由于accept()在阻塞时,可能Activity已经finish掉了,所以再次检查keepRunning
if (keepRunning)
{
Log.d(TAG, "new client coming !"); new InteractClientSocketThread(interactClientSocket).start();
}
}
catch (IOException e)
{
e.printStackTrace(); keepRunning = false;
}
} if (serverSocket != null)
{
try
{
serverSocket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
} private class InteractClientSocketThread extends Thread
{
private LocalSocket interactClientSocket; public InteractClientSocketThread(LocalSocket interactClientSocket)
{
this.interactClientSocket = interactClientSocket;
} @Override
public void run()
{
StringBuilder recvStrBuilder = new StringBuilder();
InputStream inputStream = null;
try
{
inputStream = interactClientSocket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
char[] buf = new char[4096];
int readBytes = -1;
while ((readBytes = inputStreamReader.read(buf)) != -1)
{
String tempStr = new String(buf, 0, readBytes);
recvStrBuilder.append(tempStr);
}
}
catch (IOException e)
{
e.printStackTrace(); Log.d(TAG, "resolve data error !");
}
finally
{
if (inputStream != null)
{
try
{
inputStream.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}
/* 内部类end */
}

客户端代码如下:

 package main.activity;

 import android.app.Activity;
import android.os.Bundle;
import android.util.Log; /**
* @author pengyiming
* @note 用于启动localSocketClient,向server发送心跳报文
*
*/ public class LocalSocketClientActivity extends Activity
{
/* 数据段begin */
private final String TAG = "client"; private HeartBeatThread mHeartBeatThread; public native int startHeartBeat();
/* 数据段end */ /* 函数段begin */
static
{
System.loadLibrary("pymclient");
} @Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState); mHeartBeatThread = new HeartBeatThread();
mHeartBeatThread.start();
} @Override
protected void onDestroy()
{
super.onDestroy(); mHeartBeatThread.stopRun();
}
/* 函数段end */ /* 内部类begin */
private class HeartBeatThread extends Thread
{
int ret;
boolean keepRunning = true; public void stopRun()
{
keepRunning = false;
} @Override
public void run()
{
Log.d(TAG, "start heart beat!"); while (keepRunning)
{
ret = startHeartBeat(); Log.d(TAG, "ret = " + ret); if (ret != 0)
{
break;
} try
{
sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
} Log.d(TAG, "stop heart beat!");
}
}
/* 内部类end */
}

上述客户端代码启动了一个线程用于发送“心跳”报文,每隔1s构建一个新的LocalSocket,连接服务端并发送流数据,其核心就在于native方法的实现。值得一提的是,我最初使用原生socket函数,没想connect总是返回错误;后来在同事的提醒下,我参考了Android源码rild.c中socket_local_client的使用,并从socket_local_client.c中抽取出相应代码改写而成。

客户端native方法头文件:

 /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class main_activity_LocalSocketClientActivity */ #ifndef _Included_main_activity_LocalSocketClientActivity
#define _Included_main_activity_LocalSocketClientActivity
#ifdef __cplusplus
extern "C" {
#endif /* socket命名空间(见cutils/sockets.h) */
#define ANDROID_SOCKET_NAMESPACE_ABSTRACT 0
#define ANDROID_SOCKET_NAMESPACE_RESERVED 1
#define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2 /* socket类型 */
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SOCK_RAW 3
#define SOCK_RDM 4
#define SOCK_SEQPACKET 5
#define SOCK_PACKET 10 /* 清0宏 */
#define MEM_ZERO(pDest, destSize) memset(pDest, 0, destSize) /* 错误码定义 */
#define NO_ERR 0
#define CREATE_ERR -1
#define CONNECT_ERR -2
#define LINUX_MAKE_ADDRUN_ERROR -3
#define NO_LINUX_MAKE_ADDRUN_ERROR -4
#define CLOSE_ERR -5 /* 是否使用linux的本地socket命令空间 */
#define HAVE_LINUX_LOCAL_SOCKET_NAMESPACE "linux_local_socket_namespace" #undef main_activity_LocalSocketClientActivity_MODE_PRIVATE
#define main_activity_LocalSocketClientActivity_MODE_PRIVATE 0L
#undef main_activity_LocalSocketClientActivity_MODE_WORLD_READABLE
#define main_activity_LocalSocketClientActivity_MODE_WORLD_READABLE 1L
#undef main_activity_LocalSocketClientActivity_MODE_WORLD_WRITEABLE
#define main_activity_LocalSocketClientActivity_MODE_WORLD_WRITEABLE 2L
#undef main_activity_LocalSocketClientActivity_MODE_APPEND
#define main_activity_LocalSocketClientActivity_MODE_APPEND 32768L
#undef main_activity_LocalSocketClientActivity_MODE_MULTI_PROCESS
#define main_activity_LocalSocketClientActivity_MODE_MULTI_PROCESS 4L
#undef main_activity_LocalSocketClientActivity_BIND_AUTO_CREATE
#define main_activity_LocalSocketClientActivity_BIND_AUTO_CREATE 1L
#undef main_activity_LocalSocketClientActivity_BIND_DEBUG_UNBIND
#define main_activity_LocalSocketClientActivity_BIND_DEBUG_UNBIND 2L
#undef main_activity_LocalSocketClientActivity_BIND_NOT_FOREGROUND
#define main_activity_LocalSocketClientActivity_BIND_NOT_FOREGROUND 4L
#undef main_activity_LocalSocketClientActivity_BIND_ABOVE_CLIENT
#define main_activity_LocalSocketClientActivity_BIND_ABOVE_CLIENT 8L
#undef main_activity_LocalSocketClientActivity_BIND_ALLOW_OOM_MANAGEMENT
#define main_activity_LocalSocketClientActivity_BIND_ALLOW_OOM_MANAGEMENT 16L
#undef main_activity_LocalSocketClientActivity_BIND_WAIVE_PRIORITY
#define main_activity_LocalSocketClientActivity_BIND_WAIVE_PRIORITY 32L
#undef main_activity_LocalSocketClientActivity_BIND_IMPORTANT
#define main_activity_LocalSocketClientActivity_BIND_IMPORTANT 64L
#undef main_activity_LocalSocketClientActivity_BIND_ADJUST_WITH_ACTIVITY
#define main_activity_LocalSocketClientActivity_BIND_ADJUST_WITH_ACTIVITY 128L
#undef main_activity_LocalSocketClientActivity_CONTEXT_INCLUDE_CODE
#define main_activity_LocalSocketClientActivity_CONTEXT_INCLUDE_CODE 1L
#undef main_activity_LocalSocketClientActivity_CONTEXT_IGNORE_SECURITY
#define main_activity_LocalSocketClientActivity_CONTEXT_IGNORE_SECURITY 2L
#undef main_activity_LocalSocketClientActivity_CONTEXT_RESTRICTED
#define main_activity_LocalSocketClientActivity_CONTEXT_RESTRICTED 4L
#undef main_activity_LocalSocketClientActivity_RESULT_CANCELED
#define main_activity_LocalSocketClientActivity_RESULT_CANCELED 0L
#undef main_activity_LocalSocketClientActivity_RESULT_OK
#define main_activity_LocalSocketClientActivity_RESULT_OK -1L
#undef main_activity_LocalSocketClientActivity_RESULT_FIRST_USER
#define main_activity_LocalSocketClientActivity_RESULT_FIRST_USER 1L
#undef main_activity_LocalSocketClientActivity_DEFAULT_KEYS_DISABLE
#define main_activity_LocalSocketClientActivity_DEFAULT_KEYS_DISABLE 0L
#undef main_activity_LocalSocketClientActivity_DEFAULT_KEYS_DIALER
#define main_activity_LocalSocketClientActivity_DEFAULT_KEYS_DIALER 1L
#undef main_activity_LocalSocketClientActivity_DEFAULT_KEYS_SHORTCUT
#define main_activity_LocalSocketClientActivity_DEFAULT_KEYS_SHORTCUT 2L
#undef main_activity_LocalSocketClientActivity_DEFAULT_KEYS_SEARCH_LOCAL
#define main_activity_LocalSocketClientActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L
#undef main_activity_LocalSocketClientActivity_DEFAULT_KEYS_SEARCH_GLOBAL
#define main_activity_LocalSocketClientActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L
/*
* Class: main_activity_LocalSocketClientActivity
* Method: startHeartBeat
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_main_activity_LocalSocketClientActivity_startHeartBeat
(JNIEnv *, jobject); #ifdef __cplusplus
}
#endif
#endif

客户端native方法实现:

 /* 头文件begin */
#include "main_activity_LocalSocketClientActivity.h" #include <sys/socket.h>
#include <sys/un.h>
#include <stddef.h>
#include <string.h>
/* 头文件end */ #ifdef __cplusplus
extern "C" {
#endif /*
* Class: main_activity_LocalSocketClientActivity
* Method: startHeartBeat
*/
JNIEXPORT jint JNICALL Java_main_activity_LocalSocketClientActivity_startHeartBeat(JNIEnv * env, jobject object)
{
int socketID;
struct sockaddr_un serverAddr;
char path[] = "pym_local_socket\0";
int ret; socketID = socket_local_client(path, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
if (socketID < )
{
return socketID;
} ret = close(socketID);
if (ret < )
{
return CLOSE_ERR;
} return NO_ERR;
} /* 创建本地socket客户端 */
int socket_local_client(const char *name, int namespaceId, int type)
{
int socketID;
int ret; socketID = socket(AF_LOCAL, type, );
if(socketID < )
{
return CREATE_ERR;
} ret = socket_local_client_connect(socketID, name, namespaceId, type);
if (ret < )
{
close(socketID); return ret;
} return socketID;
} /* 连接到相应的fileDescriptor上 */
int socket_local_client_connect(int fd, const char *name, int namespaceId, int type)
{
struct sockaddr_un addr;
socklen_t socklen;
size_t namelen;
int ret; ret = socket_make_sockaddr_un(name, namespaceId, &addr, &socklen);
if (ret < )
{
return ret;
} if(connect(fd, (struct sockaddr *) &addr, socklen) < )
{
return CONNECT_ERR;
} return fd;
} /* 构造sockaddr_un */
int socket_make_sockaddr_un(const char *name, int namespaceId, struct sockaddr_un *p_addr, socklen_t *socklen)
{
size_t namelen; MEM_ZERO(p_addr, sizeof(*p_addr));
#ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE namelen = strlen(name); // Test with length +1 for the *initial* '\0'.
if ((namelen + ) > sizeof(p_addr->sun_path))
{
return LINUX_MAKE_ADDRUN_ERROR;
}
p_addr->sun_path[] = ;
memcpy(p_addr->sun_path + , name, namelen); #else namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX); /* unix_path_max appears to be missing on linux */
if (namelen > (sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - ))
{
return NO_LINUX_MAKE_ADDRUN_ERROR;
} strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);
strcat(p_addr->sun_path, name); #endif p_addr->sun_family = AF_LOCAL;
*socklen = namelen + offsetof(struct sockaddr_un, sun_path) + ; return NO_ERR;
} #ifdef __cplusplus
}
#endif

注意到100~101行比较特殊,是从p_addr->sun_path[1]开始拷贝本地域名,这就是之前为什么一直connect不上的原因,至于为什么偏移1个字节来拷贝本地域名,你可以在*nix系统下输入"man 7 unix"来找到原因。

  先启动server,再启动client就可以看到结果了。对了,在成功创建并已自动连接后,我并未发送任何数据,其实发送数据就是写入文件,It's your trun now! 在close之前加入这段代码吧~

 int ret;
char buf[] = "hello"; ret = write(socketID, buf, strlen(buf));

Android利用LocalSocket实现Java端进程与C端进程之间的IPC的更多相关文章

  1. Android利用Fiddler进行网络数据抓包

    最新最准确内容建议直接访问原文:Android利用Fiddler进行网络数据抓包 主要介绍Android及IPhone手机上如何进行网络数据抓包,比如我们想抓某个应用(微博.微信.墨迹天气)的网络通信 ...

  2. Android利用Fiddler进行网络数据抓包,手机抓包工具汇总

    Fiddler抓包工具 Fiddler抓包工具很好用的,它可以干嘛用呢,举个简单例子,当你浏览网页时,网页中有段视频非常好,但网站又不提供下载,用迅雷下载你又找不到下载地址,这个时候,Fiddler抓 ...

  3. android的NDK和java进行本地socket通信

    关于Android应用与Framework的socket通信,相信关心这个问题的朋友们已经看过<android使用socket使底层和framework通信>这篇文章,美中不足的是作者只贴 ...

  4. 我的Android进阶之旅------>Android利用Sensor(传感器)实现水平仪功能的小例

    这里介绍的水平仪,指的是比较传统的气泡水平仪,在一个透明圆盘内充满液体,液体中留有一个气泡,当一端翘起时,该气泡就会浮向翘起的一端.    利用方向传感器返回的第一个参数,实现了一个指南针小应用. 我 ...

  5. [转][android][利用JNI技术在Android中调用、调试C++代码]

    在Android中调用C++其实就是在Java中调用C++代码,只是在windows下编译生成DLL,在Android中会生成Linux系统下的.so文件(好吧,其实我基本没用过Linux). 没写过 ...

  6. Android利用Fiddler进行网络数据抓包,手机抓包工具汇总,使用mono运行filddler

    Fiddler抓包工具 Fiddler抓包工具很好用的,它可以干嘛用呢,举个简单例子,当你浏览网页时,网页中有段视频非常好,但网站又不提供下载,用迅雷下载你又找不到下载地址,这个时候,Fiddler抓 ...

  7. [Java]Hessian客户端和服务端代码例子

    简要说明:这是一个比较简单的hessian客户端和服务端,主要实现从客户端发送指定的数据量到服务端,然后服务端在将接收到的数据原封不动返回到客户端.设计该hessian客户端和服务端的初衷是为了做一个 ...

  8. Android 利用Service实现下载网络图片至sdk卡

    package com.example.myapp5; import android.app.Activity; import android.content.Intent; import andro ...

  9. android利用数字证书对程序签名

     签名的必要性 1.  防止你已安装的应用被恶意的第三方覆盖或替换掉. 2.  开发者的身份标识,签名可以防止抵赖等事件的发生. 开发Android的人这么多,完全有可能大家都把类名,包名起成了一个同 ...

随机推荐

  1. Alpha Version Release Of Teamwork: Appendix 1 BUG BASH

    在为期一周的发布周中,我们将app本身最后的细节完善,功能代码到位,UI不断改进和优化,团队在开始准备发布之前,对整个APP进行了一次BUG检查,每个人都部署了app在自己的android设备上进行测 ...

  2. 第三周 构造一个简单的Linux系统MenuOS

    一.   Linux内核源代码简介 稳定版内核:Linux-3.18.6 Linux内核源代码的目录结构: arch目录:在Linux内核源代码里占有的比重很大,因为Linux内核支持很多的体系结构, ...

  3. 个人作业-Week 2 代码复审

    一.概要部分 1.代码能符合需求和规格说明么? 经过我自己的测试和助教的检测,他的代码符合需求和规格的说明. 2.代码设计是否有周全的考虑? 这里代码设计我们是从两个方面检查的: 对方处理控制台输入的 ...

  4. layout图形化界面看不到内容 Failed to find the style corresponding to the id

    1.问题 在创建新的工程的时候,选择目标SDK为api21,编译SDK为api23.创建出来的layout文件图形化界面中看不到,并且报错: Failed to find the style corr ...

  5. 淘宝卖家搜索器V1.6算法注册机。

    该软件的算法非常简单,适合小白练手.(E语言写的)1.OD加载该软件,输入bp MessageBoxA 2.点击注册 3.OD就会中断下来了 4.按ALT+K打开调用堆栈 5.往上翻,就来到算法处了 ...

  6. 新版 Chrome Ajax 跨域调试

    一.前言 web 开发中 Ajax 是十分常见的技术,但是在前后端使用接口对接的调试过程中不可避免会碰到跨域问题.今天我给大家介绍一个十分简单有效的方法. 跨域经典错误 二.Chrome 跨域设置 首 ...

  7. 【设计模式】—— 中介者模式Mediator

    前言:[模式总览]——————————by xingoo 模式意图 使用一个中介的对象,封装一组对象之间的交互,这样这些对象就可以不用彼此耦合. 这个中介者常常起着中间桥梁的作用,使其他的对象可以利用 ...

  8. P4932 浏览器

    题目背景 __stdcall在用Edge玩slay的时候,鼠标会经常失灵,这让她十分痛苦,因此她决定也要让你们感受一下Edge制造的痛苦. 题目描述 __stdcall给了你n个点,第i个点有权值x[ ...

  9. FortiGate 硬件加速

    FortiGate 硬件加速 来源 https://wenku.baidu.com/view/07749195a1c7aa00b52acb63.html 硬件加速 来源 https://blog.cs ...

  10. 【刷题】LOJ 6001 「网络流 24 题」太空飞行计划

    题目描述 W 教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合 \(E = \{ E_1, E_2, \cdots, E_m ...