本文主要是介绍NDK学习笔记(十一) POSIX Sockect 本地通信,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 1.本地通信,原生服务端、java客户端
- (1)函数介绍(C/C++)
1.本地通信,原生服务端、java客户端
这个例子中,原生代码实现了本地服务端,java代码实现了本地客户端。本地服务端使用了之前tcp通信的某些方法。
(1)函数介绍(C/C++)
创建原生本地socket
/*** 创建原生本地socket* @param env* @param obj* @return*/
static int NewLocalSocket(JNIEnv *env, jobject obj) {LogMessage(env, obj, "创建本地socket");int localSocket = socket(PF_LOCAL, SOCK_STREAM, 0);if (-1 == localSocket) {ThrowErrnoException(env, "java/io/IOException", errno);}return localSocket;
}
将本地socket与Name绑定
本地socket命名空间:
Abstract namespace:在本地socket通信协议模块中维护,socket名以NULL字符为前缀绑定socket名。
Filesystem namespace:通过文件系统以一个特殊socket文件的形式维护,socket名直接传递给sockaddr_un结构,将socket名与socket绑定。
/*** 将本地socket与某一名称绑定**/
static void BindLocalSocketToName(JNIEnv *env, jobject obj, int sd, const char *name) {struct sockaddr_un address;//长度const size_t nameLength = strlen(name);size_t pathLength = nameLength;//如果名字不以“/”开头,则在Abstract namespacebool abstractNamespace = ('/' != name[0]);//抽象命名空间要求目录的第一个字节是0字节,更新路径长度包括0字节if (abstractNamespace) {pathLength++;}if (pathLength > sizeof(address.sun_path)) {ThrowException(env, "java/io/IOException", "名字太长");} else {memset(&address, 0, sizeof(address));address.sun_family = PF_LOCAL;char *sunPath = address.sun_path;//第一字节必须是0以使用抽象命名空间if (abstractNamespace) {*sunPath++ = NULL;}strcpy(sunPath, name);//地址长度,offsetof会生成一个类型为 size_t 的整型常量,它是一个结构成员相对于结构开头的字节偏移量。socklen_t addressLength = (offsetof(struct sockaddr_un, sun_path)) + pathLength;//如果socket名已经绑定,取消连接unlink(address.sun_path);LogMessage(env, obj, "绑定到本地名称%s%s", (abstractNamespace) ? "(null)" : "", name);if (-1 == bind(sd, (struct sockaddr *) &address, addressLength)) {ThrowErrnoException(env, "java/io/IOException", errno);}}
}
接收本地socket
/*** 阻塞并等待socket上客户端的连接* @param env* @param obj* @param sd* @return*/
static int AcceptOnLocalSocket(JNIEnv *env, jobject obj, int sd) {LogMessage(env, obj, "等待客户端连接");int clientSocket = accept(sd, NULL, NULL);if (-1 == clientSocket) {ThrowErrnoException(env, "java/io/IOException", errno);}return clientSocket;
}
启动Socket Server
/*** 启动本地unix socket 服务器*/
extern "C"
JNIEXPORT void JNICALL
Java_com_example_testnt_LocalEchoActivity_nativeStartLocalServer(JNIEnv *env, jobject thiz,jstring name) {int serverSocket = NewLocalSocket(env, thiz);if (NULL == env->ExceptionOccurred()) {const char *nameText = env->GetStringUTFChars(name, NULL);if (NULL == nameText) {goto exit;}//绑定BindLocalSocketToName(env, thiz, serverSocket, nameText);env->ReleaseStringUTFChars(name, nameText);if (NULL != env->ExceptionOccurred()) {goto exit;}ListenOnSocket(env, thiz, serverSocket, 4);if (NULL != env->ExceptionOccurred()) {goto exit;}int clientSocket = AcceptOnLocalSocket(env, thiz, serverSocket);if (NULL != env->ExceptionOccurred()) {goto exit;}char buffer[MAX_BUFFER_SZIE];ssize_t recvSize;ssize_t sentSize;while (1) {recvSize = ReceiveFromSocket(env, thiz, clientSocket, buffer, MAX_BUFFER_SZIE);if ((0 == recvSize) || (NULL != env->ExceptionOccurred())) {break;}sentSize = SendToSocker(env, thiz, clientSocket, buffer, (size_t) recvSize);if ((0 == sentSize) || (NULL != env->ExceptionOccurred())) {break;}}close(clientSocket);}exit:if (serverSocket > 0) {close(serverSocket);}
}
运行效果
详细代码请看下面的连接,运行时启动LocalEchoActivity界面。
https://gitee.com/xd_box/NDK_Socket
这篇关于NDK学习笔记(十一) POSIX Sockect 本地通信的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!