java - 选择和轮询无法正常工作

标签 java c linux epoll

我在 java 中编写了一个自动流多路复用器,它必须读取大量的 FileDescriptors。要读取文件描述符(或具有 FileDescriptor 的套接字等),我需要一个精确的灵魂,如果我有一些描述符并且没有事件,请不要迭代全部。这是 linux 中的 som 方法:select,poll。我尝试使用这种方法但没有成功。 native 代码是:

JNIEXPORT jint JNICALL Java_hu_ddsi_java_Native_JUnix_select(JNIEnv * env,jobject obj,jobjectArray fds,long timeout_s,long timeout_us)
{

    int len = env->GetArrayLength(fds);
    jclass cls = env->FindClass("java/io/FileDescriptor");
    jfieldID fid = env->GetFieldID(cls, "fd", "I");
    fd_set watch;
    int buf = 0;
    int max = 0;

    for(int i=0;i <  len;i++)
    {
        FD_SET( buf=(int) env->GetIntField(env->GetObjectArrayElement(fds, i),fid),&watch);
        if(buf>max)
            max = buf;
    }

    struct timeval *timeout = (timeval*) malloc(sizeof(struct timeval));
    timeout->tv_sec = timeout_s;
    timeout->tv_usec = timeout_us;

    return select(max+1, &watch, NULL,NULL,timeout);
}

JNIEXPORT jint JNICALL Java_hu_ddsi_java_Native_JUnix_poll(JNIEnv * env,jobject obj,jlongArray pollfds,int timeout_ms)
{
    unsigned int nfds = env->GetArrayLength(pollfds);

    void* pointerfor = malloc(nfds*(sizeof(void*)));

    for(int i=0;i <  nfds;i++)
        env->GetLongArrayRegion(pollfds,i,1,(jlong*) pointerfor+(sizeof(void*)*i));

    return poll( ((struct pollfd*)pointerfor), nfds,timeout_ms);
}

JNIEXPORT jlong JNICALL Java_hu_ddsi_java_Native_JUnix_pollfd(JNIEnv * env,jobject obj,jobject fd,jshort events,jshort revents)
{
    jclass cls = env->FindClass("java/io/FileDescriptor");
    jfieldID fid = env->GetFieldID(cls, "fd", "I");

    struct pollfd *pfd = (pollfd*) malloc(sizeof( pollfd));
        pfd->fd = env->GetIntField(fd,fid);
        pfd->events = events;
        pfd->revents = 0x0;

    return (jlong) pfd; 
}

JNIEXPORT jint JNICALL Java_hu_ddsi_java_Native_JUnix_pollfdfd(JNIEnv * env,jobject obj,jlong pfd_struct)
{
    return ((struct pollfd*)pfd_struct)->fd;
}

JNIEXPORT jshort JNICALL Java_hu_ddsi_java_Native_JUnix_pollfdevents(JNIEnv * env,jobject obj,jlong pfd_struct)
{
    return ((struct pollfd*)pfd_struct)->events;
}

JNIEXPORT jshort JNICALL Java_hu_ddsi_java_Native_JUnix_pollfdrevents(JNIEnv * env,jobject obj,jlong pfd_struct)
{
    return ((struct pollfd*)pfd_struct)->revents;
}

Java 中的测试代码:

    public static void main(String args[]) throws Throwable

        final FileInputStream is = new FileInputStream("/var/log/apache2/access.log");
        long st = JUnix.pollfd(is.getFD(),(short)( JUnix.POLLIN|JUnix.POLLPRI ));
        int len = 0;
        while(true)
        {

            System.out.println("ava:"+(len = is.available()));

            for(int i=0;i < len;i++)
                System.out.print((char) is.read());

//          JUnix.select(new FileDescriptor[]{is.getFD()},5,0);

            System.out.println("pollretval: "+JUnix.poll(new long[]{st},-1));
            System.out.println("revent: "+JUnix.pollfdrevents(st));
            System.out.println("pollfd: "+JUnix.pollfdfd(st));
        }
    }

当我浏览时,我应该在终端中看到新行,但它会永远被阻止...... 如果我修改超时,我会在我的终端中看到现在的行。

有时代码会变得疯狂并无限打印:

ava:0
pollretval: 1
revent: 0
pollfd: 10

这个结果很有趣,fileDescriptor 是相同的, native poll 返回修改后的 fd 编号,但在 pollfd 结构中,revent 字段是......如果事件发生,它应该被修改。 我测试过,指针的位置很好(如结果所示),一个简单的 C 代码也有相同的结果(我没有在 C 中找到类似 InputStream.available 的 FD 方法,所以我看不到流中有多少字节可用, 但它会永远等待)

我做错了什么?

最佳答案

Java_hu_ddsi_java_Native_JUnix_select 中你需要添加一个调用

FD_ZERO(&watch);

初始化你的fd_set

您还泄漏了超时。您需要在 select 返回后 free 它,或者更好的是,只需在堆栈上声明它

struct timeval timeout;
timeout.tv_sec = timeout_s;
timeout.tv_usec = timeout_us;
return select(max+1, &watch, NULL,NULL,&timeout);

Java_hu_ddsi_java_Native_JUnix_poll 中也有类似的 pointerfor 泄漏。使用 malloc 可能比较合适,因此您可能需要在返回之前释放 指针。

关于java - 选择和轮询无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18176627/

相关文章:

Java - 添加到列表时出现 ConcurrentModificationException

Java递归问题

c - 我无法打印使用 "gets"函数读取的字符串

c - Linux 中 inet_addr_lst 内核符号的用途是什么?

c - 函数 _IO_file_init 和 _IO_file_fopen 的定义

java - 如何在 Java 1.4 中设置 BufferedReader 和 PrintWriter 的超时?

java - 在 IntelliJ JUnit 运行配置中共享环境变量

c - 为什么我不能递增数组?

c - 为什么在 valgrind 输出中出现错误 "...depends on uninitialised value"?

c++ - 如何直接从内存编译执行?