NDK学习笔记(十) POSIX Sockect 面向无连接的通信


下面只是代码片段,想看详细的代码请clone代码。
本人没有在android虚拟机上看到通信成功,试了好多配置依然不行,过段时间找两个手机再试试。
运行项目时,如果要看tcp的,则需要更改ClientTask、ServerTask类中的onBackground方法,将jni方法替换成tcp的。udp的也一样,udp的则替换成udp的jni方法。

地址:https://gitee.com/xd_box/NDK_Socket

1.接收数据报

__fd:socket实例
__buf:保存从socket接收的数据
__n:缓冲区大小
__flags:额外标志
__src_addr:保存客户端发送包的协议地址
__src_addr_length:协议地址的内存空间大小

成功返回接收到的字节数,失败返回-1
__socketcall ssize_t recvfrom(int __fd, void* __buf, size_t __n, int __flags, struct sockaddr* __src_addr, socklen_t* __src_addr_length);
static ssize_t ReceiveDatagramFromSocket(JNIEnv *env, jobject obj, int sd,
                                         struct sockaddr_in *address, char *buffer,
                                         size_t bufferSize) {

    socklen_t addressLength = sizeof(struct sockaddr_in);
    //从socket中接受数据包
    LogMessage(env, obj, "从socket接受数据");
    ssize_t recvSize = recvfrom(sd, buffer, bufferSize, 0, (struct sockaddr *) address,
                                &addressLength);

    if (-1 == recvSize) {

        ThrowErrnoException(env, "java/io/IOException", errno);
    } else {

        LogAddress(env, obj, "接收到", address);
        //以NULL种植缓冲区使其为一个字符串
        buffer[recvSize] = NULL;

        if (recvSize > 0) {

            LogMessage(env, obj, "接收到%d字节:%s", recvSize, buffer);
        }
    }
    return recvSize;
}

2.发送数据报

__fd:socket实例
__buf:要发送的数据的指针
__n:缓冲区大小
__flags:额外标志
__dst_addr:目标地址
__dst_addr_length:地址结构大小

成功返回传送的字节数,失败但会-1
__socketcall ssize_t sendto(int __fd, const void* __buf, size_t __n, int __flags, const struct sockaddr* __dst_addr, socklen_t __dst_addr_length);
static ssize_t SendDatagramToSpcket(JNIEnv *env, jobject obj, int sd,
                                    const struct sockaddr_in *address, const char *buffer,
                                    size_t bufferSize) {

    LogAddress(env, obj, "Sending to", address);
    ssize_t sentSize = sendto(sd, buffer, bufferSize, 0, (const sockaddr *) address,
                              sizeof(struct sockaddr_in));
    if (-1 == sentSize) {

        ThrowErrnoException(env, "java/io/IOException", errno);
    } else if (sentSize > 0) {

        LogMessage(env, obj, "sent %d 字节:%s", sentSize, buffer);
    }
    return sentSize;
}

3.udp服务

开启udp服务

extern "C"
JNIEXPORT void JNICALL
Java_com_example_testnt_EchoServerActivity_nativeStartUdpServer(JNIEnv *env, jobject thiz,
                                                                jint port) {

    int serverSocket = NewUdpSocket(env, thiz);
    if (NULL == env->ExceptionOccurred()) {

        BindSocketToPort(env, thiz, serverSocket, (unsigned short) port);
        if (NULL != env->ExceptionOccurred()) {

            goto exit;
        }
        if (0 == port) {

            GetSocketPort(env, thiz, serverSocket);
            if (NULL != env->ExceptionOccurred()) {
                goto exit;
            }
        }
        struct sockaddr_in address;
        memset(&address, 0, sizeof(address));

        char buffer[MAX_BUFFER_SZIE];
        ssize_t recvSize;
        ssize_t sentSize;

        //接收
        recvSize = ReceiveDatagramFromSocket(env, thiz, serverSocket, &address, buffer,
                                             MAX_BUFFER_SZIE);
        if ((0 == recvSize) || (NULL != env->ExceptionOccurred())) {

            goto exit;
        }
        sentSize = SendDatagramToSpcket(env, thiz, serverSocket, &address, buffer,
                                        (size_t) recvSize);
        if ((0 == sentSize) || (NULL != env->ExceptionOccurred())) {

            goto exit;
        }
    }
    exit:
    if (serverSocket > 0) {

        close(serverSocket);
    }
}

4.udp客户端

extern "C"
JNIEXPORT void JNICALL
Java_com_example_testnt_EchoClientActivity_nativeStartUdpClient(JNIEnv *env, jobject thiz,
                                                                jstring ip, jint port,
                                                                jstring message) {
    int clientSocket = NewUdpSocket(env, thiz);
    if (NULL == env->ExceptionOccurred()) {

        struct sockaddr_in address;
        memset(&address, 0, sizeof(address));
        address.sin_family = PF_INET;

        const char *ipAddress = env->GetStringUTFChars(ip, NULL);
        if (NULL == ipAddress) {
            goto exit;
        }
        //将IP地址字符串转换为网络地址
        int result = inet_aton(ipAddress, &(address.sin_addr));
        env->ReleaseStringUTFChars(ip, ipAddress);

        if (0 == result) {

            ThrowErrnoException(env, "java/io/IOException", errno);
            goto exit;
        }
        //转换为网络字节顺序
        address.sin_port = htons(port);

        const char *messageText = env->GetStringUTFChars(message, NULL);
        if (NULL == messageText) {
            goto exit;
        }

        jsize messageSize = env->GetStringUTFLength(message);

        //发送
        SendDatagramToSpcket(env, thiz, clientSocket, &address, messageText, (size_t) messageSize);
        env->ReleaseStringUTFChars(message, messageText);

        //失败
        if (NULL != env->ExceptionOccurred()) {
            goto exit;
        }

        char buffer[MAX_BUFFER_SZIE];
        memset(&address, 0, sizeof(address));

        ReceiveDatagramFromSocket(env, thiz, clientSocket, &address, buffer, MAX_BUFFER_SZIE);

    }
    exit:
    if (clientSocket > 0) {

        close(clientSocket);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值