博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android利用LocalSocket实现Java端进程与C端进程之间的IPC
阅读量:3523 次
发布时间:2019-05-20

本文共 15513 字,大约阅读时间需要 51 分钟。

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。

服务端代码如下:

1 package main.activity;  2   3 import java.io.IOException;  4 import java.io.InputStream;  5 import java.io.InputStreamReader;  6   7 import android.app.Activity;  8 import android.net.LocalServerSocket;  9 import android.net.LocalSocket; 10 import android.os.Bundle; 11 import android.util.Log; 12  13 /** 14  * @author pengyiming 15  * @note 启动localSocketServer 16  * 17  */ 18  19 public class LocalSocketServerActivity extends Activity 20 { 21     /* 数据段begin */ 22     private final String TAG = "server"; 23      24     private ServerSocketThread mServerSocketThread; 25     /* 数据段end */ 26      27     /* 函数段begin */ 28     @Override 29     protected void onCreate(Bundle savedInstanceState) 30     { 31         super.onCreate(savedInstanceState); 32          33         mServerSocketThread = new ServerSocketThread(); 34         mServerSocketThread.start(); 35     } 36      37     @Override 38     protected void onDestroy() 39     { 40         super.onDestroy(); 41          42         mServerSocketThread.stopRun(); 43     } 44     /* 函数段end */ 45      46     /* 内部类begin */ 47     private class ServerSocketThread extends Thread 48     { 49         private boolean keepRunning = true; 50         private LocalServerSocket serverSocket; 51          52         private void stopRun() 53         { 54             keepRunning = false; 55         } 56          57         @Override 58         public void run() 59         { 60             try 61             { 62                 serverSocket = new LocalServerSocket("pym_local_socket"); 63             } 64             catch (IOException e) 65             { 66                 e.printStackTrace(); 67                  68                 keepRunning = false; 69             } 70              71             while(keepRunning) 72             { 73                 Log.d(TAG, "wait for new client coming !"); 74                  75                 try 76                 { 77                     LocalSocket interactClientSocket = serverSocket.accept(); 78                      79                     //由于accept()在阻塞时,可能Activity已经finish掉了,所以再次检查keepRunning 80                     if (keepRunning) 81                     { 82                         Log.d(TAG, "new client coming !"); 83                          84                         new InteractClientSocketThread(interactClientSocket).start(); 85                     } 86                 } 87                 catch (IOException e) 88                 { 89                     e.printStackTrace(); 90                      91                     keepRunning = false; 92                 } 93             } 94              95             if (serverSocket != null) 96             { 97                 try 98                 { 99                     serverSocket.close();100                 }101                 catch (IOException e)102                 {103                     e.printStackTrace();104                 }105             }106         }107     }108     109     private class InteractClientSocketThread extends Thread110     {111         private LocalSocket interactClientSocket;112         113         public InteractClientSocketThread(LocalSocket interactClientSocket)114         {115             this.interactClientSocket = interactClientSocket;116         }117         118         @Override119         public void run()120         {121             StringBuilder recvStrBuilder = new StringBuilder();122             InputStream inputStream = null;123             try124             {125                 inputStream = interactClientSocket.getInputStream();126                 InputStreamReader inputStreamReader = new InputStreamReader(inputStream);127                 char[] buf = new char[4096];128                 int readBytes = -1;129                 while ((readBytes = inputStreamReader.read(buf)) != -1)130                 {131                     String tempStr = new String(buf, 0, readBytes);132                     recvStrBuilder.append(tempStr);133                 }134             }135             catch (IOException e)136             {137                 e.printStackTrace();138                 139                 Log.d(TAG, "resolve data error !");140             }141             finally142             {143                 if (inputStream != null)144                 {145                     try146                     {147                         inputStream.close();148                     }149                     catch (IOException e)150                     {151                         e.printStackTrace();152                     }153                 }154             }155         }156     }157     /* 内部类end */158 }

 客户端代码如下:

1 package main.activity; 2  3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.util.Log; 6  7 /** 8  * @author pengyiming 9  * @note 用于启动localSocketClient,向server发送心跳报文10  *11  */12 13 public class LocalSocketClientActivity extends Activity14 {15     /* 数据段begin */16     private final String TAG = "client";17     18     private HeartBeatThread mHeartBeatThread;19     20     public native int startHeartBeat();21     /* 数据段end */22     23     /* 函数段begin */24     static25     {26         System.loadLibrary("pymclient");27     }28     29     @Override30     protected void onCreate(Bundle savedInstanceState)31     {32         super.onCreate(savedInstanceState);33         34         mHeartBeatThread = new HeartBeatThread();35         mHeartBeatThread.start();36     }37     38     @Override39     protected void onDestroy()40     {41         super.onDestroy();42         43         mHeartBeatThread.stopRun();44     }45     /* 函数段end */46     47     /* 内部类begin */48     private class HeartBeatThread extends Thread49     {50         int ret;51         boolean keepRunning = true;52         53         public void stopRun()54         {55             keepRunning = false;56         }57         58         @Override59         public void run()60         {61             Log.d(TAG, "start heart beat!");62             63             while (keepRunning)64             {65                 ret = startHeartBeat();66                 67                 Log.d(TAG, "ret = " + ret);68                 69                 if (ret != 0)70                 {71                     break;72                 }73                 74                 try75                 {76                     sleep(1000);77                 }78                 catch (InterruptedException e)79                 {80                     e.printStackTrace();81                 }82             }83             84             Log.d(TAG, "stop heart beat!");85         }86     }87     /* 内部类end */88 }

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

客户端native方法头文件:

1 /* DO NOT EDIT THIS FILE - it is machine generated */ 2 #include 
3 /* Header for class main_activity_LocalSocketClientActivity */ 4 5 #ifndef _Included_main_activity_LocalSocketClientActivity 6 #define _Included_main_activity_LocalSocketClientActivity 7 #ifdef __cplusplus 8 extern "C" { 9 #endif10 11 /* socket命名空间(见cutils/sockets.h) */12 #define ANDROID_SOCKET_NAMESPACE_ABSTRACT 013 #define ANDROID_SOCKET_NAMESPACE_RESERVED 114 #define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 215 16 /* socket类型 */17 #define SOCK_STREAM 118 #define SOCK_DGRAM 219 #define SOCK_RAW 320 #define SOCK_RDM 421 #define SOCK_SEQPACKET 522 #define SOCK_PACKET 1023 24 /* 清0宏 */25 #define MEM_ZERO(pDest, destSize) memset(pDest, 0, destSize)26 27 /* 错误码定义 */28 #define NO_ERR 029 #define CREATE_ERR -130 #define CONNECT_ERR -231 #define LINUX_MAKE_ADDRUN_ERROR -332 #define NO_LINUX_MAKE_ADDRUN_ERROR -433 #define CLOSE_ERR -534 35 /* 是否使用linux的本地socket命令空间 */36 #define HAVE_LINUX_LOCAL_SOCKET_NAMESPACE "linux_local_socket_namespace"37 38 #undef main_activity_LocalSocketClientActivity_MODE_PRIVATE39 #define main_activity_LocalSocketClientActivity_MODE_PRIVATE 0L40 #undef main_activity_LocalSocketClientActivity_MODE_WORLD_READABLE41 #define main_activity_LocalSocketClientActivity_MODE_WORLD_READABLE 1L42 #undef main_activity_LocalSocketClientActivity_MODE_WORLD_WRITEABLE43 #define main_activity_LocalSocketClientActivity_MODE_WORLD_WRITEABLE 2L44 #undef main_activity_LocalSocketClientActivity_MODE_APPEND45 #define main_activity_LocalSocketClientActivity_MODE_APPEND 32768L46 #undef main_activity_LocalSocketClientActivity_MODE_MULTI_PROCESS47 #define main_activity_LocalSocketClientActivity_MODE_MULTI_PROCESS 4L48 #undef main_activity_LocalSocketClientActivity_BIND_AUTO_CREATE49 #define main_activity_LocalSocketClientActivity_BIND_AUTO_CREATE 1L50 #undef main_activity_LocalSocketClientActivity_BIND_DEBUG_UNBIND51 #define main_activity_LocalSocketClientActivity_BIND_DEBUG_UNBIND 2L52 #undef main_activity_LocalSocketClientActivity_BIND_NOT_FOREGROUND53 #define main_activity_LocalSocketClientActivity_BIND_NOT_FOREGROUND 4L54 #undef main_activity_LocalSocketClientActivity_BIND_ABOVE_CLIENT55 #define main_activity_LocalSocketClientActivity_BIND_ABOVE_CLIENT 8L56 #undef main_activity_LocalSocketClientActivity_BIND_ALLOW_OOM_MANAGEMENT57 #define main_activity_LocalSocketClientActivity_BIND_ALLOW_OOM_MANAGEMENT 16L58 #undef main_activity_LocalSocketClientActivity_BIND_WAIVE_PRIORITY59 #define main_activity_LocalSocketClientActivity_BIND_WAIVE_PRIORITY 32L60 #undef main_activity_LocalSocketClientActivity_BIND_IMPORTANT61 #define main_activity_LocalSocketClientActivity_BIND_IMPORTANT 64L62 #undef main_activity_LocalSocketClientActivity_BIND_ADJUST_WITH_ACTIVITY63 #define main_activity_LocalSocketClientActivity_BIND_ADJUST_WITH_ACTIVITY 128L64 #undef main_activity_LocalSocketClientActivity_CONTEXT_INCLUDE_CODE65 #define main_activity_LocalSocketClientActivity_CONTEXT_INCLUDE_CODE 1L66 #undef main_activity_LocalSocketClientActivity_CONTEXT_IGNORE_SECURITY67 #define main_activity_LocalSocketClientActivity_CONTEXT_IGNORE_SECURITY 2L68 #undef main_activity_LocalSocketClientActivity_CONTEXT_RESTRICTED69 #define main_activity_LocalSocketClientActivity_CONTEXT_RESTRICTED 4L70 #undef main_activity_LocalSocketClientActivity_RESULT_CANCELED71 #define main_activity_LocalSocketClientActivity_RESULT_CANCELED 0L72 #undef main_activity_LocalSocketClientActivity_RESULT_OK73 #define main_activity_LocalSocketClientActivity_RESULT_OK -1L74 #undef main_activity_LocalSocketClientActivity_RESULT_FIRST_USER75 #define main_activity_LocalSocketClientActivity_RESULT_FIRST_USER 1L76 #undef main_activity_LocalSocketClientActivity_DEFAULT_KEYS_DISABLE77 #define main_activity_LocalSocketClientActivity_DEFAULT_KEYS_DISABLE 0L78 #undef main_activity_LocalSocketClientActivity_DEFAULT_KEYS_DIALER79 #define main_activity_LocalSocketClientActivity_DEFAULT_KEYS_DIALER 1L80 #undef main_activity_LocalSocketClientActivity_DEFAULT_KEYS_SHORTCUT81 #define main_activity_LocalSocketClientActivity_DEFAULT_KEYS_SHORTCUT 2L82 #undef main_activity_LocalSocketClientActivity_DEFAULT_KEYS_SEARCH_LOCAL83 #define main_activity_LocalSocketClientActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L84 #undef main_activity_LocalSocketClientActivity_DEFAULT_KEYS_SEARCH_GLOBAL85 #define main_activity_LocalSocketClientActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L86 /*87 * Class: main_activity_LocalSocketClientActivity88 * Method: startHeartBeat89 * Signature: ()I90 */91 JNIEXPORT jint JNICALL Java_main_activity_LocalSocketClientActivity_startHeartBeat92 (JNIEnv *, jobject);93 94 #ifdef __cplusplus95 }96 #endif97 #endif

客户端native方法实现:

1 /* 头文件begin */  2 #include "main_activity_LocalSocketClientActivity.h"  3   4 #include 
5 #include
6 #include
7 #include
8 /* 头文件end */ 9 10 #ifdef __cplusplus 11 extern "C" { 12 #endif 13 14 /* 15 * Class: main_activity_LocalSocketClientActivity 16 * Method: startHeartBeat 17 */ 18 JNIEXPORT jint JNICALL Java_main_activity_LocalSocketClientActivity_startHeartBeat(JNIEnv * env, jobject object) 19 { 20 int socketID; 21 struct sockaddr_un serverAddr; 22 char path[] = "pym_local_socket\0"; 23 int ret; 24 25 socketID = socket_local_client(path, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); 26 if (socketID < 0) 27 { 28 return socketID; 29 } 30 31 ret = close(socketID); 32 if (ret < 0) 33 { 34 return CLOSE_ERR; 35 } 36 37 return NO_ERR; 38 } 39 40 /* 创建本地socket客户端 */ 41 int socket_local_client(const char *name, int namespaceId, int type) 42 { 43 int socketID; 44 int ret; 45 46 socketID = socket(AF_LOCAL, type, 0); 47 if(socketID < 0) 48 { 49 return CREATE_ERR; 50 } 51 52 ret = socket_local_client_connect(socketID, name, namespaceId, type); 53 if (ret < 0) 54 { 55 close(socketID); 56 57 return ret; 58 } 59 60 return socketID; 61 } 62 63 /* 连接到相应的fileDescriptor上 */ 64 int socket_local_client_connect(int fd, const char *name, int namespaceId, int type) 65 { 66 struct sockaddr_un addr; 67 socklen_t socklen; 68 size_t namelen; 69 int ret; 70 71 ret = socket_make_sockaddr_un(name, namespaceId, &addr, &socklen); 72 if (ret < 0) 73 { 74 return ret; 75 } 76 77 if(connect(fd, (struct sockaddr *) &addr, socklen) < 0) 78 { 79 return CONNECT_ERR; 80 } 81 82 return fd; 83 } 84 85 /* 构造sockaddr_un */ 86 int socket_make_sockaddr_un(const char *name, int namespaceId, struct sockaddr_un *p_addr, socklen_t *socklen) 87 { 88 size_t namelen; 89 90 MEM_ZERO(p_addr, sizeof(*p_addr)); 91 #ifdef HAVE_LINUX_LOCAL_SOCKET_NAMESPACE 92 93 namelen = strlen(name); 94 95 // Test with length +1 for the *initial* '\0'. 96 if ((namelen + 1) > sizeof(p_addr->sun_path)) 97 { 98 return LINUX_MAKE_ADDRUN_ERROR; 99 }100 p_addr->sun_path[0] = 0;101 memcpy(p_addr->sun_path + 1, name, namelen);102 103 #else104 105 namelen = strlen(name) + strlen(FILESYSTEM_SOCKET_PREFIX);106 107 /* unix_path_max appears to be missing on linux */108 if (namelen > (sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1))109 {110 return NO_LINUX_MAKE_ADDRUN_ERROR;111 }112 113 strcpy(p_addr->sun_path, FILESYSTEM_SOCKET_PREFIX);114 strcat(p_addr->sun_path, name);115 116 #endif117 118 p_addr->sun_family = AF_LOCAL;119 *socklen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;120 121 return NO_ERR;122 }123 124 #ifdef __cplusplus125 }126 #endif

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

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

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

 

 

转载地址:http://yeqqj.baihongyu.com/

你可能感兴趣的文章
N11-sql注入(http头注入)
查看>>
N2-sqlmap初使用
查看>>
N12-sql盲注原理以及boolean盲注案例实现
查看>>
N13-sqli盲注 基于时间型
查看>>
N1 技术心得 2019-6-26
查看>>
N1-环境配置
查看>>
N2-审计方法与步骤
查看>>
N3-常见的INI配置
查看>>
代码审计 N4 常见危险函数和特殊函数(一)
查看>>
MySQL笔记
查看>>
计算机运算方法之(原码 补码 反码 移码)
查看>>
计算机组成原理之(二进制与十进制互相转换,数的定点表示与浮点数表示)例题:设浮点数字长16位,其中阶码5位(含有1位阶符),尾数11位(含有1位数符)
查看>>
冒泡排序及其优化
查看>>
选择排序(java代码实现)
查看>>
插入排序
查看>>
哈夫曼树java代码实现
查看>>
快速排序
查看>>
vue路由高亮的两种方式
查看>>
vue router 报错: Uncaught (in promise) NavigationDuplicated {_name:""NavigationDuplicated"... 的解决方法
查看>>
vue跳转页面的两种方式
查看>>