2011-09-20 112 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創建線程而其他線程保持不變,那麼它就可以工作!

這就是我發現的。也許,這是不正確的。請指出。 任何建議將不勝感激!