与TCP类型的C/S相比较,UDP缺少了connetc(),listen(),acept()函数,这是用于UDP协议无连接的特性,不用维护TCP的连接,断开状态
服务器端大体的流程为建立套接字,套接字与地址结构进行绑定,收发数据,关闭套接字,分别对应于函数socket(),bind(),sendto()
recvfrom()和close
先建立套接字文件描述符,使用函数socket(),生成套接字描述符
#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain,int type,int protocol);
用户调用socket函数,然后这个函数调用系统调用函数sys_socket(),系统调用sys_socket()分为两部分,一部分生成内核socket结构,另一部分与文件描述符进行绑定,将绑定的文件描述符返回。
所以我们可以通过访问套接字描述符的方式去和内核空间交互
然后第二步就是将套接字描述符与一个地址结构绑定在一起,使用函数bind
#include<sys/types.h>
#include<sys/socket.h>
int bind(int sockfd,const struct sockaddr *my_addr,socklen_t addrlen);
与TCP并没有什么差异,bind()函数的作用是将一个套接字文件描述符与一个本地地址绑定在一起,即把发送数据的端口地址和IP地址进行了指定。
当成绑定之后,就可以使用recvfrom接收数据了
#include<sys/types.h>
#include<sys/socket.h>
ssize_t recv(int s,void *buf,size_t len,int flags);
ssize_t recvfrom(int s,void *buf,size_t len,int flags,struct sockaddr *from,socklen_t *fromlen);
可以看出来recvfrom主要是比recv函数多了一个本地地址结构,所以不需要进行连接,只需要接收时指定发送方地址就可以
然后下来是我们的客户端
大体为创建套接字,提取服务器端地址结构,收发数据
前面两个步骤上面有提到,主要是发数据的话,要用到sendto()
#include<sys/types.h>
#include<sys/socket.h>
ssize_t send(int s,const void*buf,size_t len,int flags);
ssize_t sendto(int s,const void *buf,size_t len,int flags,const struct sockaddr *to,socklen_t tolen);
和send主要区别就在于第4个参数,表示接收数据的主机地址信息,第5个参数为第4个参数所指向内容的长度
具体代码如下
服务器端
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<netinet/in.h>
#include<stdlib.h>
#define BUFF_LEN 256
void udpserv_echo(int s,struct sockaddr *client)
{
int n; //接收数据长度
char buff[BUFF_LEN]; //接收发送缓冲区
socklen_t len; //地址长度
while(1) {
len = sizeof(*client);
n = recvfrom(s,buff,BUFF_LEN,0,client,&len);
sendto(s,buff,n,0,client,len); //将接收到的字符发送回客户端
}
}
int main(void)
{
int s; //套接字文件描述符
struct sockaddr_in local; //本地的地址信息
struct sockaddr_in from; //发送方的地址信息
int from_len = sizeof(from); //地址结构的长度
int n; //接收到的数据长度
char buf[128]; //接受数据缓冲区
s= socket(AF_INET,SOCK_DGRAM,0); //初始化一个IPV4族的数据报套接字
if(-1 == s) {
perror("");
exit(EXIT_FAILURE);
}
local.sin_family = AF_INET;
local.sin_port = htons(8888);
local.sin_addr.s_addr = htonl(INADDR_ANY);
bind(s,(struct sockaddr *)&local,sizeof(local));
udpserv_echo(s,(struct sockaddr *)&from); //回显处理函数
return 0;
}
客户端
#include<sys/types.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#define PORT_SERV 8888
#define BUFF_LEN 256
void udpclie_echo(int s,struct sockaddr *to)
{
char buff[BUFF_LEN];
struct sockaddr_in from;
socklen_t len = sizeof(*to);
sendto(s,buff,BUFF_LEN,0,to,len); //发送给服务器
recvfrom(s,buff,BUFF_LEN,0,(struct sockaddr *)&from,&len); //从服务器接收数据
printf("recved:%s\n",buff);
}
int main(int argc,char *argv[])
{
int s; //文件描述符
struct sockaddr_in addr_serv; //地址结构
s = socket(AF_INET,SOCK_DGRAM,0); //建立UDP类型套接字
memset(&addr_serv,0,sizeof(addr_serv)); //清空地址结构
addr_serv.sin_family = AF_INET;
addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);
addr_serv.sin_port = htons(PORT_SERV); //服务器端口
udpclie_echo(s,(struct sockaddr *)&addr_serv); //与服务器交互
close(s);
return 0;
}