2011-09-20 111 views
0

我编写了一个本地方法,可以从套接字接收数据,然后回写到ByteArray,它是来自Java的输入参数。该套接字在BlueZ中创建并通过dBus消息传输到我的程序中。我使用单独的线程来完成整个过程。JNI投票问题

感谢Cerber对我以前的GetPrimitiveArrayCritical()问题的建议。现在,该程序可以运行没有错误。

但是,新问题是因为我使用Poll来等待POLLIN事件,如果有传入数据可供读取,理论上会有POLLIN事件,并且我可以执行套接字读取。

不幸POLLIN事件不断被触发,但我无法读取任何数据! 但是,当我在BlueZ的代码中完成同样的过程时,这种奇怪的行为没有发生。 我确定插座是正确的。

这件作品的我的本机代码是这样的:

struct socket_loop_native_data { 
     pthread_mutex_t thread_mutex; 
     pthread_t thread; 
     struct pollfd *pollData; 
     JavaVM *vm; 
     int envVer; 
     jobject me; 
     jbyteArray javaBuffer; 
     int bufferSize; 
     jbyte *nativeBuffer; 
     char *beginOfBuffer; 
     char *endOfBuffer; 
     int decodedDataSize; 
     bool running; 
}; 

typedef socket_loop_native_data native_data_t; 

static jfieldID field_mNativeDataSocket; 

static inline native_data_t *get_native_data(JNIEnv *env, jobject object) { 
    return (native_data_t *)(env->GetIntField(object, field_mNativeDataSocket)); 
} 

native_data_t *get_SocketLoop_native_data(JNIEnv *env, jobject object) { 
    return get_native_data(env, object); 
} 

JNIEXPORT void JNICALL Java_android_classInitNativeSocket(JNIEnv* env, jclass clazz) { 
    field_mNativeDataSocket = env->GetFieldID(clazz, "mNativeDataSocket", "I"); 
} 

JNIEXPORT void JNICALL Java_android_initializeNativeDataNativeSocket(JNIEnv* env, jobject object) { 

    native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t)); 
    if (NULL == nat) { 
     LOGD("%s: out of memory!", __FUNCTION__); 
     return; 
    } 
    memset(nat, 0, sizeof(native_data_t)); 

    pthread_mutex_init(&(nat->thread_mutex), NULL); 

    env->SetIntField(object, field_mNativeDataSocket, (jint)nat); 

} 

JNIEXPORT jboolean JNICALL Java_android_startSocketLoopNative(JNIEnv *env, jobject object, jint sock, jbyteArray buffer, jint size) { 

    jboolean result = JNI_FALSE; 

    socket_loop_native_data *nat = get_native_data(env, object); 

    pthread_mutex_lock(&(nat->thread_mutex)); 

    nat->running = false; 

    if (nat->pollData) { 
     LOGD("trying to start SocketLoop a second time!"); 
     pthread_mutex_unlock(&(nat->thread_mutex)); 
     return JNI_FALSE; 
    } 

    nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd)); 
    if (!nat->pollData) { 
     LOGD("out of memory error starting SocketLoop!"); 
     goto done; 
    } 

    memset(nat->pollData, 0, sizeof(struct pollfd)); 

    nat->pollData[0].fd = sock; 
    nat->pollData[0].events = POLLIN; 

    env->GetJavaVM(&(nat->vm)); 
    nat->envVer = env->GetVersion(); 

    nat->me = env->NewGlobalRef(object); 

    nat->javaBuffer = (jbyteArray)(env->NewGlobalRef(buffer)); 
    nat->bufferSize = (int)size; 
    nat->decodedDataSize = 0; 

    pthread_create(&(nat->thread), NULL, socketLoopMain, nat); 
    result = JNI_TRUE; 

done: 
    if (JNI_FALSE == result) { 
     if (nat->me) env->DeleteGlobalRef(nat->me); 
     nat->me = NULL; 
     if (nat->pollData) free(nat->pollData); 
     nat->pollData = NULL; 
    } 

    pthread_mutex_unlock(&(nat->thread_mutex)); 

    return result; 
} 

static void *socketLoopMain(void *ptr) { 

    native_data_t *nat = (native_data_t *)ptr; 
    JNIEnv *env; 

    JavaVMAttachArgs args; 
    char name[] = "SocketLoop"; 
    args.version = nat->envVer; 
    args.name = name; 
    args.group = NULL; 

    nat->vm->AttachCurrentThread(&env, &args); 

    /* For poll result */ 
    int ret = 0; 

    /* For receiving pollin data */ 
    int rlen; 
    char *buffer = (char *)calloc(1, 65536); 

    ... 

    while ((nat->running)) { 

     if ((ret = poll(nat->pollData, 1, -1)) < 0){ 
      LOGD("In socketLoopMain() : The socket poll error !!!"); 
      goto close; 
     } 

      if ((nat->pollData[0].revents & POLLIN)){ 

        ... 

       rlen = read(nat->pollData[0].fd, buffer, 65536); 
       LOGD("In socketLoopMain() : Read bytes = %d", rlen); 

        ... 
      } 

      else if ((nat->pollData[0].revents & POLLOUT)){ 
       LOGD("In socketLoopMain() : The socket poll revents [POLLOUT] !!! DO NOTHING"); 
       continue; 
      } 
      else if ((nat->pollData[0].revents & POLLERR)){ 
       LOGD("In socketLoopMain() : The socket poll revents [POLLERR] !!!"); 
       goto close; 
      } 
      else if ((nat->pollData[0].revents & POLLHUP)){ 
       LOGD("In socketLoopMain() : The socket poll revents [POLLHUP] !!!"); 
       goto close; 
      } 
      else if ((nat->pollData[0].revents & POLLRDHUP) || (nat->pollData[0].revents & POLLNVAL)){ 
       LOGD("In socketLoopMain() : The socket poll revents [POLLRDHUP][POLLNVAL] !!!"); 
       goto close; 
      } 
    } 
    ... 
} 

除了第一POLLIN,我无法读取套接字的任何数据,RLEN始终为0

我建立整个本地代码通过在Android源代码根目录中使用命令“make libxxx”而不是“ndk-build”来共享lib。

任何建议将不胜感激!

回答

0

一些实验后,我发现(我不知道,如果这是正常和正确的行为或不...)

(1)在JNI,当客户端本身关闭连接的插座中,服务器不会意识到这一点。服务器部分会持续接收POLLIN事件,但如果我们读取套接字,则读取的字节数将为0! (2)在JNI中,当服务器轮询套接字超时并关闭连接的套接字时,客户端不会意识到这一点。如果客户端尝试通过此封闭套接字发送数据,则会收到返回值-1。 (3)在JNI中,如果我使用pthread_create并处理套接字,则无论是否将此线程附加到Java VM,套接字都将无法正常工作!但是如果我用Java创建线程而其他线程保持不变,那么它就可以工作!

这就是我发现的。也许,这是不正确的。请指出。 任何建议将不胜感激!