android 把socket 提到JNI层实现
来源:互联网 发布:众银家苹果下载软件 编辑:程序博客网 时间:2024/06/03 20:00
设计背景:
1. APP 需要不断与中控系统进行数据包通信,设计分包,重发 机制,负荷压力大,在JAVA层实现,效率慢,于是提到JNI 层实现.
JAVA
private native void initUDPSocket(int port);private native String getLocalSocketIP();private native void sendData(String ip, int port, byte[] data, int len);private native void freeSocket();
2.JNI:
//MAX data buffer size#define MAX_BUFFER_SIZE 1024static void BindSocketToPort(JNIEnv* env, jobject obj, int sd, unsigned short port); void* ReceiveFromSocket(void* args);static int m_udpSocket;static int m_isExit = 0;static JavaVM* gVm = NULL;static jobject gObj = NULL;static jmethodID gOnReceiveData = NULL;char* TAG= "NATIVE_UDPMANAGER";jint JNI_OnLoad(JavaVM* vm, void* reserved){ gVm = vm; return JNI_VERSION_1_4;}//初始化JNIEXPORT void JNICALL Java_com_controlService_UDPManager_initUDPSocket (JNIEnv * env, jobject obj, jint port){ if(NULL == gObj){ gObj = (*env)->NewGlobalRef(env,obj); if(NULL == gObj) return; } if(NULL == gOnReceiveData){ jclass clazz = (*env)->GetObjectClass(env,obj); gOnReceiveData = (*env)->GetMethodID(env,clazz,"onReceiveData","(Ljava/lang/String;I[B)V"); (*env)->DeleteLocalRef(env,clazz); if(NULL == gOnReceiveData) __android_log_print(ANDROID_LOG_ERROR, TAG,"GetMethodID error"); } __android_log_print(ANDROID_LOG_INFO, TAG,"Constructing a new UDP socket..."); m_udpSocket = socket(PF_INET, SOCK_DGRAM,0); if( -1 == m_udpSocket){ ThrowErrnoException(env,"java/io/IOException",errno); } BindSocketToPort(env,obj,m_udpSocket,(unsigned short)port); //线程句柄 pthread_t thread; int result = pthread_create(&thread,NULL,ReceiveFromSocket,NULL); if(0 != result){ jclass ex = (*env)->FindClass(env,"java/lang/RuntimeException"); (*env)->ThrowNew(env,ex,"Unable to create thread"); }}JNIEXPORT void JNICALL Java_com_controlService_UDPManager_sendData(JNIEnv *env, jobject obj, jstring ip, jint port, jbyteArray data, jint len){ struct sockaddr_in address; memset(&address, 0, sizeof(address)); address.sin_family = PF_INET; //以C字符串形式获取IP地址 const char* ipAddress = (*env)->GetStringUTFChars(env,ip, NULL); if(NULL == ipAddress){ __android_log_print(ANDROID_LOG_ERROR, TAG,"wrong ip.."); return; } //将IP地址字符串转换为网络地址 int result = inet_aton(ipAddress, &(address.sin_addr)); //释放IP地址 (*env)->ReleaseStringUTFChars(env,ip, ipAddress); //如果转换失败 if( 0 == result){ ThrowErrnoException(env,"java/io/IOException", errno); return; } //将端口转换转换为网络字节顺序 address.sin_port = htons(port); //将本地指针指向含有Java端数组的内存地址,依赖JVM的具体实现 //可能是锁住java端的数组不被回收(增加引用计数),也可能在jvm所在的堆上拷贝一份 //速度和效率比GetByteArrayRegion方法高很多 unsigned char * cdata = (*env)->GetByteArrayElements(env, data, NULL); if(NULL == cdata){ __android_log_print(ANDROID_LOG_ERROR, TAG,"GetByteArrayElements failed..."); return; } ssize_t sendSize = sendto(m_udpSocket, cdata, (size_t)len, 0, &address, sizeof(struct sockaddr_in)); (*env)->ReleaseByteArrayElements(env,data,cdata,0); if( -1 == sendSize){ ThrowErrnoException(env,"java/io/IOException", errno); }}JNIEXPORT void JNICALL Java_com_controlService_UDPManager_freeSocket (JNIEnv * env, jobject obj){ if(NULL != gObj) { (*env)->DeleteGlobalRef(env,gObj); gObj = NULL; } m_isExit = 1; close(m_udpSocket);}static void BindSocketToPort(JNIEnv* env, jobject obj, int sd, unsigned short port) { struct sockaddr_in address; //清空结构体 memset(&address, 0, sizeof(address)); address.sin_family = PF_INET; //Bind to all address address.sin_addr.s_addr = htonl(INADDR_ANY); //Convert port to network byte order address.sin_port = htons(port); //Bind socket __android_log_print(ANDROID_LOG_INFO, TAG,"bind port:%d",port); // 设置套接字选项避免地址使用错误 int on=1; if((setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0) { __android_log_print(ANDROID_LOG_ERROR, TAG,"setsockopt failed"); exit(EXIT_FAILURE); } //sockaddr方便函数传递, sockaddr_in方便用户设定, 所以需要的时候在这2者之间进行转换 if (-1 == bind(sd, (struct sockaddr*) &address, sizeof(address))) { ThrowErrnoException(env, "java/io/IOException", errno); } int broadcastEnable=1; int ret=setsockopt(sd, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)); if(ret < 0) { __android_log_print(ANDROID_LOG_ERROR, TAG,"ERROR BROADCASTING, Coulnt set broadcast enable through socket options"); }}JNIEXPORT jstring JNICALL Java_com_controlService_UDPManager_getLocalSocketIP (JNIEnv *env, jobject obj){ jstring jip = NULL; struct sockaddr_in address; socklen_t addressLength = sizeof(address); if (-1 == getsockname(m_udpSocket, (struct sockaddr*) &address, &addressLength)) { ThrowErrnoException(env, "java/io/IOException", errno); } else { char *ip = inet_ntoa(address.sin_addr); jip =(*env)->NewStringUTF(env,ip); } return jip;}//接收 recv()void* ReceiveFromSocket(void* args) { JNIEnv* env = NULL; if(0 == (*gVm)->AttachCurrentThread(gVm,&env,NULL)){ unsigned char buffer[MAX_BUFFER_SIZE]; //客户端地址 struct sockaddr_in address; while(!m_isExit){ memset(&address,0, sizeof(address)); socklen_t addressLen = sizeof(struct sockaddr_in); ssize_t recvSize = recvfrom(m_udpSocket, buffer, MAX_BUFFER_SIZE - 1, 0,&address,&addressLen); if (-1 == recvSize) { ThrowErrnoException(env, "java/io/IOException", errno); } else if(recvSize != 0){ __android_log_print(ANDROID_LOG_INFO, TAG,"received data..."); //字符串截断 buffer[recvSize] = '0'; //分配 jbyteArray array = (*env)->NewByteArray(env,recvSize); (*env)->SetByteArrayRegion(env,array,0,recvSize,buffer); char *ip = inet_ntoa(address.sin_addr); __android_log_print(ANDROID_LOG_INFO, TAG,"received data from %s",ip); jstring jip =(*env)->NewStringUTF(env,ip); if(NULL == jip){ __android_log_print(ANDROID_LOG_ERROR, TAG,"could not new java string.."); } jint port = ntohs(address.sin_port); (*env)->CallVoidMethod(env,gObj,gOnReceiveData,jip,port,array); (*env)->DeleteLocalRef(env,array); (*env)->DeleteLocalRef(env,jip); } } (*gVm)->DetachCurrentThread(gVm); } return (void*)1;}
0 0
- android 把socket 提到JNI层实现
- Android Jni层 创建 linux socket 出错问题解决
- android的 Local Socket 的JNI实现
- Android GPS学习笔记—JNI层实现
- Android GPS学习笔记(3)—JNI层实现
- android jni socket
- android jni socket
- android jni socket
- android: jni socket
- android jni socket
- Android Socket通信--通过jni用c++实现客户端
- Android C++ Socket请求XMl,TinyXml解析文件,JNI返回数据给JAVA层
- Android JNI实现简单的c层调用Java层函数(C层调用Java层Toast进行提示)
- Android framework层自定义jni
- 把WINDOW提到最前
- socket层---accept的实现
- cocos2d-x 通过JNI实现c/c++和Android的java层函数互调
- cocos2d-x 通过JNI实现c/c++和Android的java层函数互调
- 专业名词
- 264. Ugly Number II 类别:动态规划 难度:medium
- pod升级以及更新不到最新的第三方库解决方法
- LeetCode OJ-3.Longest Substring Without Repeating Characters(最长无重复子串)
- JavaScript笔记(1)
- android 把socket 提到JNI层实现
- Nginx学习总结(5)——Nginx基本配置备忘
- redis的事件驱动
- logback+slf4j日志框架
- (笔记)VB中修改字体大小、日期加减,oracle数据库中查询条件为日期类型
- 隐式类型转换系统是很好的.
- java 静态方法和实例方法的区别
- 有道云笔记图片链接
- [代码笔记] python 之JSON 使用和 Time,datetime