我编写了一个本机方法,可以从socket接收数据,然后写回ByteArray,这是来自Java的输入参数。套接字是在BlueZ中创建的,并通过dBus消息传输到我的程序。我使用一个单独的线程来完成整个过程。
感谢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”将整个本机代码构建到共享库。
任何建议都将非常感谢!!!
答案 0 :(得分:0)
经过一些实验,我发现(我不确定这是否是正常和正确的行为......)
(1)在JNI中,当客户端本身关闭连接的套接字时,服务器不会意识到这一点。服务器部分将连续接收POLLIN事件但如果我们读取套接字,则读取的字节将为0 !!!
(2)在JNI中,当服务器轮询套接字超时并关闭连接的套接字时,客户端将不会意识到这一点。如果客户端尝试通过此关闭的套接字发送数据,则会收到返回值-1。
(3)在JNI中,如果我使用pthread_create并处理套接字,无论你是否将此线程附加到Java VM,套接字都无法正常工作!但是如果我用Java创建线程,而其他线程保持不变,它就可以工作!
这就是我发现的。也许,这是不正确的。请指出。 任何建议都将非常感谢!!!
答案 1 :(得分:0)
此页面将为您提供答案。 http://developer.android.com/training/articles/perf-jni.html