本文共 5439 字,大约阅读时间需要 18 分钟。
从一个图示开始:
从上述图示中我们都可以看到,UDP的传输相对来说比TCP传输的时候要简单很多,因为其不需要建立稳定连接,只是相互端口之间的发送,对于一些传输效率需求比较高的应用场景来说,是比较适合的,但是其在稳定性,可靠性上就有一定差异了发送数据:
#includessize_t send(int sockfd,const void* buf,size_t nbytes,int flag);(调用connect过后可以直接调用send方法)返回:成功返回发送字节数,出错返回-1ssize_t sendto(int sockfd,const void * buf,size_t nbytes,int flag,const struct sockaddr * destaddr,socklen_t destlen);返回:成功返回发送字节数,出错返回-1ssize_t sendmsg(int sockfd,const struct msghdr *msg,int flag);返回:成功返回发送字节数,出错返回-1struct msghdr{ void *msg_name; /**/ socklen_t msg_namelen;/**/ struct iovec * msg_iov;/**/ int msgiovlen; /**/ void *msg_control;/**/ socklen_t msg_controllen;/**/ int msg_flag;/**/}
接收数据
#includessize_t recv(int sockfd,void *buf,size_t nbytes,int flag); ssize_t recvfrom(int sockfd,void * restrict buf,size_t len,int flag,struct sockaddr* restrict addr,socklen_t *restrict addrlen); 一般flag为0; ssize_t recvmsg(int sockfd,struct msghdr *msg,int flag); 返回:返回消息的字节数,无消息返回0,出错返回-1
不多说上代码
/* * =========================================================================== * * Filename: udp_server.c * Description: * 基于udp协议的一个server端的程序(udp协议没有差错校验)面向无连接的不可靠的协议 * Version: 1.0 * Created: 2017年05月13日 09时27分26秒 * Revision: none * Compiler: gcc * Author: (), * Company: * * =========================================================================== */#include#include #include #include #include #include #include #include #include #include int sockfd;void sig_handler(int signo){ if(signo == SIGINT){ perror("sig interrupt and pid cancel"); exit(1); close(sockfd); }}void out_client_info(struct sockaddr_in *clientaddr){ char ip[16]; int port; memset(ip,0,sizeof(ip)); inet_ntop(AF_INET,&clientaddr->sin_addr.s_addr,ip,sizeof(ip)); port = ntohs(clientaddr->sin_port); printf("client:%s(%d)\n",ip,port);}void do_service(){ struct sockaddr_in clientaddr; socklen_t len = sizeof(clientaddr); char buff[1024]; memset(&clientaddr,0,len); ssize_t size = recvfrom(sockfd,buff,sizeof(buff),0,(struct sockaddr *)&clientaddr,&len); if(size < 0 ){ printf("recv error"); }else{ out_client_info(&clientaddr); printf("client send info:%s\n",buff); time_t t = time(0); char *ptr = ctime(&t); ssize_t time_size = strlen(ptr) * sizeof(char); if(sendto(sockfd,ptr,time_size,0,(struct sockaddr*)&clientaddr,len) < 0){ perror("send to error"); } }}int main(int argc,char *argv[]){ //确定绑定的端口,从命令行传入参数,第二个参数是绑定端口的参数 if(argc < 2){ printf("usage :%s port\n",argv[0]); exit(EXIT_FAILURE); } if(signal(SIGINT,sig_handler) == SIG_ERR){ perror("signal sigint error"); exit(EXIT_FAILURE); } /* * *创建socket * * */ sockfd = socket(AF_INET,SOCK_DGRAM,0); if(sockfd < 0 ){ perror("socket create error"); exit(EXIT_FAILURE); } int res; int opt = 1; /* * *设置端口停止后,后续端口能够立马再次使用 * */ if((res = setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt))) <0){ perror("setsockopt error"); exit(1); } /* * *调用bind函数对socket和地址进行绑定 sockaddr--->socket通用地址 sockaddr_in--->socket专用地址 * */ struct sockaddr_in addr_in; memset(&addr_in,0,sizeof(addr_in)); addr_in.sin_family = AF_INET; //IPV4 addr_in.sin_port = htons(atoi(argv[1])); //端口必须要是网络字节序 addr_in.sin_addr.s_addr = INADDR_ANY; //获得主机上面所有ip地址的请求 if(bind(sockfd,(struct sockaddr *)&addr_in,sizeof(addr_in)) < 0){ //对端口进行绑定 perror("bind error"); exit(EXIT_FAILURE); } /* * * * */ while(1){ do_service(); } return 0;}
/* * =========================================================================== * * Filename: udp_client.c * Description: 基于udp协议的一个client端 * Version: 1.0 * Created: 2017年05月13日 10时09分41秒 * Revision: none * Compiler: gcc * Author: (), * Company: * * =========================================================================== */#include#include #include #include #include #include #include int client_sockfd;int main(int argc,char * argv[]){ if(argc < 3){ printf("usage :%s ip port\n",argv[0]); exit(EXIT_FAILURE); } client_sockfd = socket(AF_INET,SOCK_DGRAM,0); if(client_sockfd < 0 ){ perror("create client socket error"); exit(EXIT_FAILURE); } /** *一般在客户端是不需要去进行绑定操作的,调用recv和sendto进行双向通信 */ struct sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(serveraddr)); serveraddr.sin_family = AF_INET; //IPV4 serveraddr.sin_port = htons(atoi(argv[2]));//端口 inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr); //ip /* * *注意:如果在udp中调用connect的话,不会进行握手动作,只是在内核中去记住了地址信息,这个时候可以直接使用send去发送信息,而不需要再去进行调用sendto函数 调用connect的好处就是客户端接收到的数据报文仅仅是服务器发过来的,如果不去调用的话,则很有可能是其他服务器发过来的 * * */ int connect_result; connect_result = connect(client_sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr)); if(connect < 0){ perror("connect error"); exit(EXIT_FAILURE); } char buff[1024] = "helloworld"; ssize_t client_size_t; client_size_t = sendto(client_sockfd,buff,sizeof(buff),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr)); if(client_size_t < 0){ perror("sendto error"); exit(1); } else { memset(buff,0,sizeof(buff)); size_t size; size = recv(client_sockfd,buff,sizeof(buff),0); if(size <0){ perror("recv error"); exit(EXIT_FAILURE); }else{ printf("%s",buff); } } close(client_sockfd); return 0;}
代码都是经过调试的,udp_server端负责去接收client发过来的报文信息.
由于最近个人事情比较多,所有很长一段时间都没有去更新了.