Android NDK网络通信篇(五)之UDP通信篇

来源:互联网 发布:北塔软件规模 编辑:程序博客网 时间:2024/06/06 14:00

Android NDK网络通信篇(五)

UDP通信篇

前言

本篇重点讲解UDP通信的相关函数以及UDP服务端和客户端程序设计流程,并提供UDP C/S通信的客户端和服务端示例代码。

UDP通信相关的头文件

#include <sys/socket.h>

#include <sys/un.h>

#include <sys/endian.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <unistd.h>

UDP通信函数解析

创建UDP socket

int socket(int domain, int type, int protocal);

参数解析:

domain:指定将会产生通讯的socket域,并且选择用到的协议族。android平台目前支持以下协议族:

l  PF_LOCAL:主机内部通讯协议族,该协议族使用物理上运行在同一台设备上的应用程序可以使用Socket APIs进行通信。

l  PF_INET:IPv4协议族,该协议族使得运行的应用程序可以与网络上的其它应用程序进行通讯。

type:指通信的类型,支持以下两种类型:

SOCK_STREAM:供TCP协议使用。

SOCK_DGRAM:供UDP协议使用。

protocal:指定将会用到的协议。对于大部分协议族和协议类型来说,只能使用一个协议。为了选择默认的协议,该参数可以设为零。

如果socket创建成功,将会返回对应的socket描述符,否则返回-1。

示例代码:

int NewUdpSocket(JNIEnv*env,jobject obj){
    int sd=socket(PF_INET,SOCK_DGRAM,0);
    return sd;
}

绑定UDP socket

int bind(int socketDescriptor, const struct sockaddr* address, int addressLength);

参数解析:

socketDescriptor:指服务端socket

address:指socket要绑定的服务端地址结构体

addressLength:指定address结构体的大小

如果绑定成功,返回0,否则返回-1

示例代码:

sockaddr_in getSockaddr_in(const char *ip,int port){    sockaddr_in address;    memset(&address,0, sizeof(sockaddr_in));    address.sin_family=AF_INET;    address.sin_port=htons(port);    inet_aton(ip,&address.sin_addr);    return address;}
int BindSocket(JNIEnv *env,jobject obj,int sd,const char *ip,int port){    sockaddr_in address=getSockaddr_in(ip,port);    int result=bind(sd,(sockaddr *)&address, sizeof(address));    return result;}

接收UDP信息

ssize_t recvfrom(intsocketDescriptor, void* buffer,size_t bufferLength, intflags, const struct sockaddr* address,socklen_t* addressLength);

参数解析:

socketDescriptor:指要接收信息的socket,在客户端指服务端socket,在客户端指客户端socket

buffer:指接收数据的缓冲区

bufferLength:指接收数据的缓冲区的大小

flags:指要接收数据的附加参数

address:指sockaddr结构体,这个结构体将被填入接收方的信息

addressLength:address结构体的大小

如果函数调用成功返回接收到的数据的大小,否则返回-1

示例代码:

int server_socket= NewUdpSocket(env,gThiz);
sockaddr_in address;
socklen_t addr_len= sizeof(address);

while(true){
    char buffer[1024];
    int receive_size=recvfrom(server_socket,buffer,1024,0,(constsockaddr *)&address,&addr_len);
    if(receive_size==0||env->ExceptionOccurred()!=NULL)break;
    if(receive_size>0){
        __android_log_print(ANDROID_LOG_VERBOSE,"hello","receive datafrom client is%s",buffer);

        int send_size=sendto(server_socket,buffer,receive_size,0,(constsockaddr *)&address,addr_len);
        if(send_size==0||env->ExceptionOccurred()!=NULL)break;
        __android_log_print(ANDROID_LOG_VERBOSE,"hello","send data toclient is%s",buffer);
    }
}

发送UDP信息

ssize_t sendto(intsocketDescriptor, const void* buffer,size_t bufferLength, intflags, const struct sockaddr* address,socklen_t addressLength);

参数解析:

socketDescriptor:指要发送信息的socket,在客户端指服务端socket,在客户端指客户端socket

buffer:指发送数据的缓冲区

bufferLength:指发送数据的缓冲区的大小

flags:指要发送数据的附加参数

address:指sockaddr结构体,这个结构体将被填入接收方的信息

addressLength:address结构体的大小

如果函数调用成功返回已发送的数据的大小,否则返回-1

示例代码:

int server_socket= NewUdpSocket(env,gThiz);
sockaddr_in address;
socklen_t addr_len= sizeof(address);

while(true){
    char buffer[1024];
    int receive_size=recvfrom(server_socket,buffer,1024,0,(constsockaddr *)&address,&addr_len);
    if(receive_size==0||env->ExceptionOccurred()!=NULL)break;
    if(receive_size>0){
        __android_log_print(ANDROID_LOG_VERBOSE,"hello","receive datafrom client is%s",buffer);

        int send_size=sendto(server_socket,buffer,receive_size,0,(constsockaddr *)&address,addr_len);
        if(send_size==0||env->ExceptionOccurred()!=NULL)break;
        __android_log_print(ANDROID_LOG_VERBOSE,"hello","send data toclient is%s",buffer);
    }
}

获取客户端socket 信息

int getpeername(intsocketDescriptor, struct sockaddr* address, socklen_t* addressLength);

参数解析:

socketDescriptor:指客户端socket

address:指sockaddr结构体,这个结构体将被填入客户端的信息

addressLength:address结构体的大小

如果函数调用成功返回0,否则返回-1

示例代码:

struct SocketInfo{
    int port;
    const char *ip;
};

SocketInfo * GetClientSocketInfo(JNIEnv*env,jobject obj,intsd){
    sockaddr_in address;
    socklen_t addressLength= sizeof(address);
    getpeername(sd,(sockaddr *)&address,&addressLength);
    SocketInfo *socketInfo=newSocketInfo;
    socketInfo->port=ntohs(address.sin_port);
    socketInfo->ip=inet_ntoa(address.sin_addr);
    return socketInfo;
}

获取服务端socket信息

int getsockname(intsocketDescriptor, struct sockaddr* address, socklen_t* addressLength);

参数解析:

socketDescriptor:指服务端socket

address:指sockaddr结构体,这个结构体将被填入服务端的信息

addressLength:address结构体的大小

如果函数调用成功返回0,否则返回-1

示例代码:

struct SocketInfo{
    int port;
    const char *ip;
};

SocketInfo * GetServerSocketInfo(JNIEnv*env,jobject obj,intsd){
    sockaddr_in address;
    socklen_t addressLength= sizeof(address);
    getsockname(sd,(sockaddr *)&address,&addressLength);
    SocketInfo *socketInfo=newSocketInfo;
    socketInfo->port=ntohs(address.sin_port);
    socketInfo->ip=inet_ntoa(address.sin_addr);
    return socketInfo;
}

 

UDP服务端

UDP服务端程序流程图

1.   创建UDP socket(socket())

2.   绑定UDP socket(bind())

3.   接收UDP消息(recvfrom())

4.   发送UDP消息(sendto())

UDP服务端程序示例

void *udpServerThread(void* args){
    JNIEnv *env;
    gVM->AttachCurrentThread(&env,NULL);
    int server_socket=NewUdpSocket(env,gThiz);
   BindSocket(env,gThiz,server_socket,gServerIP,gServerPort);
    SocketInfo *serverSocketInfo=GetServerSocketInfo(env,gThiz,server_socket);
    __android_log_print(ANDROID_LOG_VERBOSE,"hello","client ip=%s,client port=%d",serverSocketInfo->ip,serverSocketInfo->port);

    sockaddr_in address;
    socklen_t addr_len= sizeof(address);

    while(true){
        char buffer[1024];
        int receive_size=recvfrom(server_socket,buffer,1024,0,(constsockaddr *)&address,&addr_len);
        if(receive_size==0||env->ExceptionOccurred()!=NULL)break;
        if(receive_size>0){
            __android_log_print(ANDROID_LOG_VERBOSE,"hello","receive datafrom client is%s",buffer);

            int send_size=sendto(server_socket,buffer,receive_size,0,(constsockaddr *)&address,addr_len);
            if(send_size==0||env->ExceptionOccurred()!=NULL)break;
            __android_log_print(ANDROID_LOG_VERBOSE,"hello","send data toclient is%s",buffer);
        }
    }

    CloseSocket(env,gThiz,server_socket);
    __android_log_print(ANDROID_LOG_VERBOSE,"hello","%s","serversocket close");

    gVM->DetachCurrentThread();

    return (void*)0;
}

extern "C"
JNIEXPORT voidJNICALL
Java_com_kgdwbb_jnistudy_MainActivity_startUDPServerSocket(JNIEnv* env,jobject thiz){
    if(gThiz==NULL){
        gThiz=env->NewGlobalRef(thiz);
    }
    pthread_t pthread;
    pthread_create(&pthread,NULL,udpServerThread,NULL);
}

UDP客户端

UDP客户端程序流程图

1.   创建客户端socket(socket())

2.   发送消息到服务器(sendto())

3.   接收服务器返回的消息(recvfrom())

UDP客户端程序示例

void * udpClientThread(void* args){
    JNIEnv *env;
    gVM->AttachCurrentThread(&env,NULL);

    int client_socket=NewUdpSocket(env,gThiz);

    sockaddr_in address=getSockaddr_in(gServerIP,gServerPort);
    socklen_t addr_len= sizeof(address);

    const char *msg="helloboy";
    int len=strlen(msg);

    int send_size=sendto(client_socket,msg,len,0,(constsockaddr *)&address,addr_len);
    if(send_size==0||env->ExceptionOccurred()!=NULL){
       CloseSocket(env,gThiz,client_socket);
        return (void*)1;
    }
    __android_log_print(ANDROID_LOG_VERBOSE,"hello","send data toserver is%s",msg);

    char buffer2[1024];
    int receive_size= recvfrom(client_socket,buffer2,1024,0,(constsockaddr *)&address,&addr_len);
    if(receive_size==0||env->ExceptionOccurred()!=NULL){
       CloseSocket(env,gThiz,client_socket);
        return (void*)1;
    }
    __android_log_print(ANDROID_LOG_VERBOSE,"hello","receiveddata from server is%s",buffer2);

    CloseSocket(env,gThiz,client_socket);
    __android_log_print(ANDROID_LOG_VERBOSE,"hello","%s","clientsocket close");

    gVM->DetachCurrentThread();

    return (void*)1;
}

extern "C"
JNIEXPORT voidJNICALL
Java_com_kgdwbb_jnistudy_MainActivity_startUDPClientSocket(JNIEnv* env,jobject thiz){
    if(gThiz==NULL){
        gThiz=env->NewGlobalRef(thiz);
    }
    pthread_t pthread;
    pthread_create(&pthread,NULL,udpClientThread,NULL);
}

结束语

本篇重点讲解了UDP通信相关的函数,以及一个完整的UDP C/S架构的通信示例,相信大家学完本篇,一定能熟悉掌握UDP通信的相关知识。记得一定要多练习,才能更好的理解UDP通信的流程。

原创粉丝点击