Select模型(PIPE)

来源:互联网 发布:日本av作品番号数据库 编辑:程序博客网 时间:2024/06/07 04:54
Linux中的函数select和poll用来支持I/O复用的功能,在Linux中I/O模型可以分为以一几种:(引用叶剑峰)
(1)阻塞I/O

这个模型也是最容易理解的

程序调用和我们基本的程序编写是一致的:

fd = connect()

write(fd)

read(fd)

close(fd)

程序的read必须在write之后执行,当write阻塞住了,read就不能执行下去


(2)非阻塞I/O

从图中可以看出来,这是一个轮询的过程
每次用户询问内核是否有数据报准备好(文件描述符缓冲区是否就绪),当数据报准备好的时候,就进行拷贝数据报的操作。当数据报没有准备好的

时候,也不阻塞程序,内核直接返回未准备就绪的信号,等待用户程序的下一次轮询。

设置非阻塞io:
#include <fcntl.h> int fcntl(int fd, int cmd, .. /* int arg */)

eg.

flags = flags | O_NONBLOCK;fcntl(fd, F_SETFL, flags);




(3)I/O复用(select和poll,epoll)

IO复用模型是多了一个select函数,select函数有一个参数是文件描述符集合,意思就是对这些的文件描述符进行循环监听,当某个文件描述符就绪的时候,就对这个文件描述符进行处理。

这种IO模型是属于阻塞的IO。但是由于它可以对多个文件描述符进行阻塞监听,所以它的效率比阻塞IO模型高效


(4)信号驱动I/O(SIGIO)

信号驱动IO模型是应用进程告诉内核:当你的数据报准备好的时候,给我发送一个信号哈,并且调用我的信号处理函数来获取数据报。这个模型是由信号进行驱动。

(5)异步I/O

异步IO使用的不再是read和write的系统接口了,应用工程序调用aio_XXXX系列的内核接口。

当应用程序调用aio_read的时候,内核一方面去取数据报内容返回,另外一方面将程序控制权还给应用进程,应用进程继续处理其他事务。这样应用进程就是一种非阻塞的状态。

当内核的数据报就绪的时候,是由内核将数据报拷贝到应用进程中,返回给aio_read中定义好的函数处理程序。



   其中,现在比较流行的I/O模型是阻塞I/O模型.阻塞I/O是当应用程序和内核交换数据时,由于内核还没有准备好数据,那么应用程序必须进行阻塞,不能继续执行,直到内核的数据准备好!应用程序取到数据返回后,阻塞过程结束!但返回的结果也并不一定是正确的!这里只是举一个简单的例子!也许情况会更加的复杂!
   非阻塞I/O,例如在和内核交换数据时,如果内核的数据没有准备好,那么应用程序不会一真等待,会有一个返回信息,以判断是那里出了问题!这样有助于确认是在那个阶段出了问题!
   I/O复用,我们就可以调用系统调用select,poll,epoll!这里不是真正的阻塞I/O系统调用!
   下面主要介绍I/O复用中的select函数!select函数可以指示内核等待多个事件中的任一个发生,仅在一个或多个事件发生,或者等待一个足够的时间后才唤醒进程!select函数的原型如下:

select函数


#include<sys/select.h>

#include<sys/time.h>

int select (int maxfd , fd_set *readset ,fd_set *writeset, fd_set *exceptionset , const struct timeval * timeout);

返回:就绪描述字的正数目,0——超时,-1——出错

 

参数解释:

maxfd: 最大的文件描述符(其值应该为最大的文件描述符字 + 1)

readset: 内核读操作的描述符字集合

writeset:内核写操作的描述符字集合

exceptionset:内核异常操作的描述符字集合

timeout:等待描述符就绪需要多少时间。NULL代表永远等下去,一个固定值代表等待固定时间,0代表根本不等待,检查描述字之后立即返回。

 

注意:readset,writeset,exceptionset都是值-结果参数,意思就是他们传进入指针进去,函数根据指针可以修改对应的fd_set


fd_set集合操作

fd_set和名字一样,是一个描述符的集合。有下面几个操作:

void FD_ZERO(fd_set *fdset); /* 将所有fd清零 */

void FD_SET(int fd, fd_set *fdset); /* 增加一个fd */

void FD_CLR(int fd, fd_set *fdset); /* 删除一个fd */

int FD_ISSET(int fd, fd_set *fdset); /* 判断一个fd是否有设置 */


下面以匿名管道程序,采用读非阻塞的select模型作为例子

jni:

#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<jni.h>#include<signal.h>#include<sys/select.h>#include<sys/time.h>#include <fcntl.h>#include <sys/types.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/Select";static char CB_METHOD[] = "callBack";static int mWakeReadPipeFd = -1;static int mWakeWritePipeFd = -1;static struct timeval timeout={3,0};static fd_set fdset;static int maxfds = -1;static int nret = -1;void DestroyUnNamePipe(JNIEnv *env, jobject thiz){if(nret == 0){close(mWakeReadPipeFd);close(mWakeWritePipeFd);}}jint CreateUnNamePipe(JNIEnv *env, jobject thiz){int ret = -1;int result = -1;int fd[2];ret = pipe(fd);nret = ret;if(ret != 0){LOGE("create unname pipe error:%d" ,ret);}else{mWakeWritePipeFd = fd[1];mWakeReadPipeFd  = fd[0];// 设置为非阻塞result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);if(result != 0){LOGE("can not set to nonblock");}result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);if(result != 0){LOGE("can not set to nonblock");}LOGE("set select mode");FD_ZERO(&fdset); //清空集合FD_SET(mWakeReadPipeFd, &fdset); //添加描述符 FD_SET(mWakeWritePipeFd, &fdset); //添加描述符 maxfds = (fd[1] > fd[0])?fd[1]+1:fd[0]+1;             }return ret;}void ReadUNPMessage(JNIEnv *env, jobject thiz){int select_ret;int ret = -1;/*select_ret = select(maxfds,&fd_set,NULL,NULL,&timeout);*/while(1){LOGE("select start");select_ret = select(maxfds, &fdset, NULL, NULL, NULL);LOGE("read ret:%d" , select_ret);if(select_ret > 0){if(FD_ISSET(mWakeReadPipeFd, &fdset) && nret == 0){//call java methodchar buffer[80+1];memset(buffer, 0, sizeof(buffer));ret = read(mWakeReadPipeFd, buffer, sizeof(buffer));LOGE("read ret:%d" , ret);if(ret == -1)return ;else{jbyteArray array = (*env)->NewByteArray(env, sizeof(buffer));(*env)->SetByteArrayRegion(env, array, 0, sizeof(buffer), (char *)buffer);jclass jhandlerClass = (*env)->GetObjectClass(env, thiz);      jmethodID doActionMethodId = (*env)->GetMethodID(env, jhandlerClass, CB_METHOD, "([B)V");      (*env)->CallVoidMethod(env, thiz, doActionMethodId, array);  (*env)->ReleaseByteArrayElements(env, array, buffer, 0);}}}}return ;}jint SendUNPMessage(JNIEnv *env, jobject thiz, jstring message){int ret = -1;if(nret == 0){const char *pMsg = (*env)->GetStringUTFChars(env, message, 0);ret = write(mWakeWritePipeFd, 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", "()V", (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;import android.util.Log;public class Select {static {// 加载动态库System.loadLibrary("JNISelect");}public native int createUnNamePipe();public native int sendUNPMessage(String msg);public native void readUNPMessage();public native void destroyUnNamePipe();public void callBack(byte[] buffer){Log.d("jacklam", "read msg:" + new String(buffer));}}

调用:

public void startSelect3(View view){if(select != null)select.destroyUnNamePipe();}public void startSelect2(View view){if(select != null){select.sendUNPMessage("test select mode");}/*mem.close(fd);*/}public void startSelect1(View view){select = new Select();select.createUnNamePipe();Thread thread = new Thread(new Runnable() {@Overridepublic void run() {select.readUNPMessage();}});thread.start();/*mem.close(fd);*/}

显示结果:



0 0
原创粉丝点击