LocalSocket实现进程间通信 android下使用localsocket可以实现C与C,C与JAVA,JAVA与JAVA进程间通信。 localsocket是linux下的一种本地套接字,用来进行进程间通信,分为非命名和命名两种类型,非命名本地套接字只能用在父子进程之间通信(其实是只有保存了未命名的套接字的文件描述符的进程可以使用),命名套接字则没有这个限制。android在linux的本地套接字上进行封装。 android上使用localsocket主要是通过name来区分,也就是说客户端和服务端之间连接必须使用相同的name,并且一个name同一时间只能有一个服务端运行,name可以只一串字符串,如“com.penguin.sk”。

c 客户端 c 服务端 java 客户端 java 服务端 c 客户端 c客户端代码主要调用的是android接口: int socket_local_server(const char *name, int namespaceId, int type) 函数读写id,read id就是接收服务端的数据,write id就是发送数据给服务端– 参数name就是上述说的客户端与服务端连接的关键name,namespaceId一般使用ANDROID_SOCKET_NAMESPACE_ABSTRACT, type 使用SOCK_STREAM。下面是客户端c demon代码:

#include <sys/socket.h> #include <sys/un.h> #include <stddef.h> #include <string.h> #include <unistd.h> #include <stdio.h> #include <cutils/sockets.h> #define PATH "com.penghui.localsocket" int main(int argc, char *argv[]) { int socketID;

int ret;
int i = 0;
int len = 0;
for(;i < argc ;i++){
    len = len + strlen(argv[i]);
}
len = len + argc ;
char *buffer ;
buffer = ( char *)malloc(len * sizeof( char *));
if(buffer == NULL){
    printf("malloc failed\n");
    return 0;
}
strcpy(buffer, argv[0]);
for(i=1;i<argc;i++){
    strcat(buffer, " "); 
    strcat(buffer, argv[i]); 
}
socketID = socket_local_client(PATH, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
if (socketID < 0)
{
    return socketID;
}
ret = write(socketID, buffer, strlen(buffer));
if(ret < 0){
    printf("send failed\n");
    return ret;
}
char buf2[512] = {0};
ret = read(socketID,buf2,sizeof(buf2));
if(ret < 0){
    printf("recived failed\n");
    return ret;
}else{
    printf("c client recived from server: %s\n",buf2);
}

ret = close(socketID);
if (ret < 0)
{
    return ret;
}

return 0;

}

c 服务端 c服务端调用 int socket_local_server(const char *name, int namespace, int type) 函数返回服务端socket,然后可以调用accept开始接受客户端请求,参数与客户端一样

#include <sys/socket.h> #include <sys/un.h> #include <stddef.h> #include <string.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <cutils/sockets.h> #include <pthread.h> #define PATH "com.penghui.localsocket" void * connectThread(void *arg); int main(int argc, char *argv[]) { int ret ; int serverID = socket_local_server(PATH, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); if(serverID < 0){ printf("socket_local_server failed :%d\n",serverID); return serverID; } int socketID; pthread_t tid; while((socketID= accept(serverID,NULL,NULL)) >=0){ ret = pthread_create(&tid,NULL,connectThread,(void *)&socketID); if(ret != 0){ printf("error create thread:%s\n",strerror(ret)); exit(1); } } return ret;

}

void * connectThread(void arg) { int ret; int socketID =(int *)arg; if(socketID < 0){ printf("socketID is %d\n",socketID); return NULL; } char buf2[512] = {0}; ret = read(socketID,buf2,sizeof(buf2)); if(ret < 0){ printf("recived failed\n"); return NULL; } printf("c server recived: %s\n",buf2); char buffer[] = {"this message from c server "}; ret = write(socketID, buffer, strlen(buffer)); if(ret < 0){ printf("write failed\n"); return NULL; } close(socketID); return NULL;

}

java 客户端 java 的服务端和客户端和网络socket基本一样,只不过网络socket是用ip和端口号连接的,localsocket使用上述说的name。 客户端代码是在android源码下编译成jar包,然后仿造android am命令(frameworks/base/cmds/am/)在clientSocket脚本里调用jar包做成可执行文件的,这种做法对jar包的包名有要求,最好是直接用com.android.commands.*开头的。

package com.android.commands.factory;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.util.Log;

public class Factory { private static final String TAG= "Factory_test"; public static void main(String[] args){ if(args.length == 0 ){ printHelp(); return ; } String command = "";
for(int i = 0;i < args.length; i++){ command = command + args[i] + " "; Log.w(TAG,"command"+command); } ClientConnect cl = new ClientConnect(); cl.connect(); cl.send(command); String result = cl.recv(); System.out.println("java client recive:"+result); cl.close();

}

private static void printHelp(){
    System.out.println(
            "\n"                                                        +
            "Usage: factory_test cmds [params]\n"                       +
            "cmds:\n"                                                   +
            "        get_eth_mac -- get ethernet mac address.\n"        +
            "        copy_log -- copy the log to usb device .\n"        
                                                                        );
}

}

class ClientConnect {
private static final String TAG = "ClientConnect";
private static final String name = "com.penghui.localsocket";
private LocalSocket Client = null;
private PrintWriter os = null;
private BufferedReader is = null;
private int timeout = 30000;

    public void connect(){    
        try {  
            Client = new LocalSocket();  
            Client.connect(new LocalSocketAddress(name));  
           // Client.setSoTimeout(timeout);  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  

    public void send(String data) {  
        try {  
            os = new PrintWriter(Client.getOutputStream());  
            os.println(data);  
            os.flush();  
            //System.out.println("client send over");  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  

    public String recv() {  
        Log.d(TAG,"recv");  
        String result = null;  
        try {  
            is = new BufferedReader(new InputStreamReader(Client.getInputStream()));  
            result = is.readLine();  
            Log.d(TAG, result);  
        } catch (IOException e) {  
            e.printStackTrace();  
        } finally {  
        }  
        return result;  
    }  

    public void close() {  
        try {  
            is.close();  
            os.close();  
            Client.close();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
}  

Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_MODULE := factory include $(BUILD_JAVA_LIBRARY)

include $(CLEAR_VARS) LOCAL_MODULE := clientSocketJava LOCAL_SRC_FILES := clientSocket LOCAL_MODULE_CLASS := EXECUTABLES LOCAL_MODULE_TAGS := optional include $(BUILD_PREBUILT)

clientSocket 脚本

base=/system export CLASSPATH=$base/framework/factory.jar exec app_process $base/bin com.android.commands.factory.Factory "$@"

java 服务端 java服务端实现在一个apk里,apk启动时开启服务端,然后就可以执行客户端命令去与服务端交互数据。

package com.example.localsocketserver;

import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket;

import android.app.Activity; import android.net.Credentials; import android.net.LocalServerSocket; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem;

public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private ServerThread mThread = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    startServer();
}

@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();

}

@Override
protected void onDestroy() {
    // TODO Auto-generated method stub
    super.onDestroy();
    stopServer();
}

private void startServer(){
    stopServer();
    mThread = new ServerThread();
    mThread.start();
}
private void stopServer(){
    if(mThread != null){
        mThread.exit();
        mThread = null;
    }
}
private class ServerThread extends Thread{
    private boolean exit = false;
    private int port = 3333;

    public void run() {  
        LocalServerSocket server = null;  
        BufferedReader mBufferedReader = null;  
        PrintWriter os = null;  
        String readString =null;  
        try {  
            server = new LocalServerSocket("com.repackaging.localsocket");        
            while (!exit) {  
                LocalSocket connect = server.accept();  
                Credentials cre = connect.getPeerCredentials();
                Log.i(TAG,"accept socket uid:"+cre.getUid()); 
                new ConnectThread(connect).start();

            }     
        } catch (IOException e) {  
            e.printStackTrace();  
        }finally{

            try {  
                mBufferedReader.close();  
                os.close();  
                server.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
    } 

    public void exit(){
        exit = true;
        this.interrupt();
        try {
            this.wait();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

class ConnectThread extends Thread{
    LocalSocket socket = null;
     BufferedReader mBufferedReader = null;  
     InputStream input = null;
     PrintWriter os = null;
     String readString =null;
    public ConnectThread(LocalSocket socket){    
        this.socket = socket;
    }

    @Override
    public void run(){
        try {
            input = socket.getInputStream();
            byte[] buffer = new byte[1024];
            int len = input.read(buffer);
             Log.d(TAG,"mBufferedReader:"+new String(buffer,0,len)); 

           /* while((readString=mBufferedReader.readLine())!=null){  
                //if(readString.equals("finish")) 
                //  break;  
                Log.d(TAG,"server recive :"+readString);  
                break;
            }  */
            os = new PrintWriter(socket.getOutputStream());  
            os.println("this is server\0");  
            os.flush();  
            os.close();
            socket.close();
            Log.d(TAG,"server send over");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

}