客户端用socket+protobuf的通信方式,封装了一个GameSocket客户端连接类,其中接受后台数据的处理是单独的一个线程
connect处理时初始化receive线程
_recv_thread = new std::thread(std::bind(&GameSocket::process_receive, this));
处理函数如下,为了避免cpu忙等和空转,socket/recv均采用阻塞方式。
void GameSocket::process_receive(void)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
if (_recv_thread) {
JavaVM *vm;
JNIEnv *env;
vm = JniHelper::getJavaVM();
JavaVMAttachArgs thread_args;
thread_args.name = "ReceiveThread";
thread_args.version = JNI_VERSION_1_4;
thread_args.group = NULL;
vm->AttachCurrentThread(&env, &thread_args);
}
#endif
log("init receive process thread");
while (true) {
unsigned char buffer;
log("###before receive invoke");
int recv_size = ::recv(_socket, buffer, BUFFER_SIZE, 0);
log("###receive thread size:%d", recv_size);
…
…
}
注意代码中红色部分,正常情况下服务器的数据发送(send),客户端recv的数据接收也是一切正常(IOS & ANDROID).
但在我需要客户端主动关闭socket时,按道理正常情况下在socket关闭时,recv调用应该返回, recv_size == 0。
socket关闭包括服务器关闭 或者客户端主动close(_socket) 或者 网络原因的断链。
但实际测试用下来这套逻辑在IOS下运行一切正常,但在android环境我测试下发只有服务器主动close,例如关闭服务器进程,客户端recv会返回0。但客户端上其他线程close(_socket),或者wifi信号掉线等原因下
recv始终不返回,一直处于挂死状态。
因为之前移植android版本时,就查到jni环境下的多线程要加上类似下面这段处理才能正常,我初步猜测这是否和jni下的多线程机制有什么关系?
但由于本人对android环境底层了解不足,这个问题google后也没明确答案,希望得到各位大拿的指点,多谢多谢!
if (_recv_thread) {
JavaVM *vm;
JNIEnv *env;
vm = JniHelper::getJavaVM();
JavaVMAttachArgs thread_args;
thread_args.name = "ReceiveThread";
thread_args.version = JNI_VERSION_1_4;
thread_args.group = NULL;
vm->AttachCurrentThread(&env, &thread_args);
}
#endif
