本篇重点讲解UDP通信的相关函数以及UDP服务端和客户端程序设计流程,并提供UDP C/S通信的客户端和服务端示例代码。
#include
#include
#include
#include
#include
#include
#include
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;
}
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; }
ssize_t recvfrom(int socketDescriptor, void* buffer, size_t bufferLength, int flags, 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,(const sockaddr *)&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,(const sockaddr *)&address,addr_len);
if(send_size==0 ||env->ExceptionOccurred()!=NULL) break;
__android_log_print(ANDROID_LOG_VERBOSE,"hello","send data toclient is %s",buffer);
}
}
ssize_t sendto(int socketDescriptor, const void* buffer, size_t bufferLength, int flags, 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,(const sockaddr *)&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,(const sockaddr *)&address,addr_len);
if(send_size==0 ||env->ExceptionOccurred()!=NULL) break;
__android_log_print(ANDROID_LOG_VERBOSE,"hello","send data toclient is %s",buffer);
}
}
int getpeername(int socketDescriptor, 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,int sd){
sockaddr_in address;
socklen_t addressLength= sizeof(address);
getpeername(sd,(sockaddr *)&address,&addressLength);
SocketInfo *socketInfo=new SocketInfo;
socketInfo->port=ntohs(address.sin_port);
socketInfo->ip=inet_ntoa(address.sin_addr);
return socketInfo;
}
int getsockname(int socketDescriptor, 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,int sd){
sockaddr_in address;
socklen_t addressLength= sizeof(address);
getsockname(sd,(sockaddr *)&address,&addressLength);
SocketInfo *socketInfo=new SocketInfo;
socketInfo->port=ntohs(address.sin_port);
socketInfo->ip=inet_ntoa(address.sin_addr);
return socketInfo;
}
1. 创建UDP socket(socket())
2. 绑定UDP socket(bind())
3. 接收UDP消息(recvfrom())
4. 发送UDP消息(sendto())
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,(const sockaddr *)&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,(const sockaddr *)&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 void JNICALL
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);
}
1. 创建客户端socket(socket())
2. 发送消息到服务器(sendto())
3. 接收服务器返回的消息(recvfrom())
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,(const sockaddr *)&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,(const sockaddr *)&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 void JNICALL
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通信的流程。