android linux进程间通信——使用匿名管道

来源:互联网 发布:淘宝充流量发验证码 编辑:程序博客网 时间:2024/06/04 19:13
一、什么是管道
如果你使用过Linux的命令,那么对于管道这个名词你一定不会感觉到陌生,因为我们通常通过符号“|"来使用管道,但是管理的真正定义是什么呢?管道是一个进程连接数据流到另一个进程的通道,它通常是用作把一个进程的输出通过管道连接到另一个进程的输入。

举个例子,在shell中输入命令:ls -l | grep string,我们知道ls命令(其实也是一个进程)会把当前目录中的文件都列出来,但是它不会直接输出,而是把本来要输出到屏幕上的数据通过管道输出到grep这个进程中,作为grep这个进程的输入,然后这个进程对输入的信息进行筛选,把存在string的信息的字符串(以行为单位)打印在屏幕上。

二、pipe调用
pipe函数的原型如下:
#include <unistd.h>  int pipe(int file_descriptor[2]);

我们可以看到pipe函数的定义非常特别,该函数在数组中墙上两个新的文件描述符后返回0,如果返回返回-1,并设置errno来说明失败原因。

数组中的两个文件描述符以一种特殊的方式连接起来,数据基于先进先出的原则,写到file_descriptor[1]的所有数据都可以从file_descriptor[0]读回来。由于数据基于先进先出的原则,所以读取的数据和写入的数据是一致的。
pipe是基于文件描述符工作的,所以在使用pipe后,数据必须要用底层的read和write调用来读取和发送。
不要用file_descriptor[0]写数据,也不要用file_descriptor[1]读数据,其行为未定义的,但在有些系统上可能会返回-1表示调用失败。数据只能从file_descriptor[0]中读取,数据也只能写入到file_descriptor[1],不能倒过来。

例子:
首先,我们在原先的进程中创建一个管道,发送消息,然后在进程中的线程接收消息(android开启进程是?),并关闭管道
jni下
#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<jni.h>#include<signal.h>#include<android/log.h>#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "native-activity", __VA_ARGS__))#ifndef NELEM# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))#endifstatic char CLASS_NAME[] = "com/sailor/Pipe";static int fd[2];static int nret = -1;void DestroyUnNamePipe(JNIEnv *env, jobject thiz){if(nret == 0){close(fd[0]);close(fd[1]);}}jint CreateUnNamePipe(JNIEnv *env, jobject thiz){int ret = -1;ret = pipe(fd);nret = ret;if(ret != 0){LOGE("create unname pipe error:%d" ,ret);}return ret;}jstring ReadUNPMessage(JNIEnv *env, jobject thiz){char buffer[80+1];int ret = -1;if(nret == 0){ret = read(fd[0], buffer, sizeof(buffer));LOGE("read ret:%d" , ret);if(ret == -1){return NULL;}}return (*env)->NewStringUTF(env, buffer);}jint SendUNPMessage(JNIEnv *env, jobject thiz, jstring message){int ret = -1;if(nret == 0){const char *pMsg = (*env)->GetStringUTFChars(env, message, 0);ret = write(fd[1], pMsg, strlen(pMsg));LOGE("send ret: %d", ret);(*env)->ReleaseStringUTFChars(env, message, pMsg);}return ret;}static JNINativeMethod mehods[] = {{ "createUnNamePipe", "()I", (void *) CreateUnNamePipe },{ "sendUNPMessage", "(Ljava/lang/String;)I", (void *) SendUNPMessage },{ "readUNPMessage", "()Ljava/lang/String;", (void *) ReadUNPMessage },{ "destroyUnNamePipe", "()V", (void *) DestroyUnNamePipe }};static int registerNativeMethods(JNIEnv *env, const char* className,                                 const JNINativeMethod* methods, int numMethods){    int rc;    jclass clazz;    clazz = (*env)->FindClass(env, className);    if (clazz == NULL) {        LOGE("Native registration unable to find class '%s'\n", className);        return -1;    }    if (rc = ((*env)->RegisterNatives(env, clazz, methods, numMethods)) < 0) {        LOGE("RegisterNatives failed for '%s' %d\n", className, rc);        return -1;    }    return 0;}static int register_jni(JNIEnv *env){return registerNativeMethods(env, CLASS_NAME, mehods, NELEM(mehods));}JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved){     JNIEnv* env = NULL;     jint result = -1;          //获取JNI版本     if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK)      {         LOGE("GetEnv failed!");             return result;     }     if (register_jni(env) < 0) {LOGE("register method failed!");             return result;     }     return JNI_VERSION_1_4;}

java下调用:
package com.sailor;public class Pipe {static {// 加载动态库System.loadLibrary("JNIPipe");}public native int createUnNamePipe();public native int sendUNPMessage(String msg);public native String readUNPMessage();public native void destroyUnNamePipe();}

public void startPipe(View view){pipe = new Pipe();pipe.createUnNamePipe();Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while(true){Log.d("jacklam", "wait read msg");Log.d("jacklam", "" + pipe.readUNPMessage());pipe.destroyUnNamePipe();break;}}});thread.start();pipe.sendUNPMessage("just test");}

当写数据的管道没有关闭,而又没有数据可读时,read调用通常会阻塞,但是当写数据的管道关闭时,read调用将会返回0而不是阻塞。注意,这与读取一个无效的文件描述符不同,read一个无效的文件描述符返回-1。

另因android sdcard为fat32,而mkfifo只是调用用mknod()来创建一个特殊的文件,和fat32不支持,所以不能创建命名管道
int mkfifo(const char *filename, mode_t mode);  



0 0