JNI Опрос проблема - PullRequest
       1

JNI Опрос проблема

0 голосов
/ 20 сентября 2011

Я пишу собственный метод, который может получать данные из сокета, а затем записывать обратно в ByteArray, который является входным параметром из Java. Сокет был создан в BlueZ и передан в мою программу с помощью сообщения dBus. Я использую отдельный поток для выполнения всей процедуры.

Спасибо за предложение Цербера по моей предыдущей проблеме GetPrimitiveArrayCritical (). Теперь программа может работать без ошибок.

Однако новая проблема заключается в том, что, поскольку я использую опрос для ожидания события 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.

Я собираю весь нативный код в общую библиотеку с помощью команды «make libxxx» в корневом каталоге исходного кода Android, а не «ndk-build».

Любое предложение будет с благодарностью !!!

Ответы [ 2 ]

0 голосов
/ 26 марта 2013

эта страница даст вам ответ. http://developer.android.com/training/articles/perf-jni.html

  1. вы не можете разделить JNIEnv между потоками.
  2. Потоки, подключенные через JNI, должны вызывать DetachCurrentThread перед выходом.
0 голосов
/ 12 октября 2011

После некоторых экспериментов я обнаружил, что (я не уверен, что это нормальное и правильное поведение или нет ...)

(1) В JNI, когда клиент сам закрывает подключенный сокет, сервер не узнает об этом. Серверная часть будет постоянно получать событие POLLIN, но если мы будем читать сокет, считанные байты будут равны 0 !!!

(2) В JNI, когда тайм-аут сокета опроса сервера и закрытие подключенного сокета, клиент не будет знать об этом. Клиент получит возвращенное значение -1, если попытается отправить данные по этому закрытому сокету.

(3) В JNI, если я использую pthread_create и обрабатываю сокет, независимо от того, присоединяете ли вы этот поток к Java VM или нет, сокет НЕ будет работать правильно !!! Но если я вместо этого создаю поток в Java, а остальные остаются прежними, это работает!

Вот что я нашел. Возможно, это не правильно. Пожалуйста, укажите. И любые предложения будут с благодарностью !!!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...