Я пишу собственный метод, который может получать данные из сокета, а затем записывать обратно в 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».
Любое предложение будет с благодарностью !!!