UDP客户/服务基本模型
UDP特点:
1.无连接
2.基于消息的数据传输服务
3.不可靠
4.一般情况下UDP更加高效
相关函数:
ssize_t recvfrom(int sockfd,void *buff,size_t nbytes,int flags, struct sockaddr *from ,socklen_t *addrlen);
ssize_t sendto(int sockfd,void *buff,size_t nbytes,int flags,const struct sockaddr *to,socklen_t *addrlen);
前三个参数sockfd,buff,nbytes等同于read和write函数的三个参数:描述符,指向读入或写出缓冲区的指针和读写字节数
flags参数暂不讨论,置为0
sendto的to参数指向一个含有数据报接收者的协议地址(例如IP地址及端口号)的套接字地址结构,其大小由addrlen指定
recvfrom的from参数指向一个将由该函数在返回时填写数据报发送者的协议地址的套接字地址结构,而在该套接字地址结构
中填写的字节数则放在addrlen参数所指的整数中返回给调用者。
注意:sendto 的最后一个参数是一个整数值,recvfrom的最后一个参数是一个指向整数值的指针。
这两个函数都是把所数据的长度作为函数返回值。
注:参考《UNIX网络编程》187页
服务器:
#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <signal.h> #include <poll.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ }while(0); \ void echo_srv(int sock) { char recvbuf[1024] = {0}; struct sockaddr_in peeraddr; socklen_t peerlen; int n; while(1) { peerlen = sizeof(peeraddr); memset(recvbuf,0,sizeof(recvbuf)); n = recvfrom(sock,recvbuf,sizeof(recvbuf),0,(struct sockaddr*)&peeraddr,&peerlen); if (n == -1) { if (errno == EINTR) continue; ERR_EXIT("recvform"); } else if (n > 0) { fputs(recvbuf,stdout); sendto(sock,recvbuf,n,0,(struct sockaddr*)&peeraddr,peerlen); } } close(sock); } int main(void) { int sock; /*0表示内核自己选择协议*/ if ((sock = socket(PF_INET,SOCK_DGRAM,0)) < 0) ERR_EXIT("socket"); struct sockaddr_in servaddr; memset(&servaddr,0,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5188); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); if ((bind(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))) < 0) ERR_EXIT("bind"); echo_srv(sock); return 0; }客户端:
#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <signal.h> #include <poll.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ }while(0); \ void echo_cli(int sock) { struct sockaddr_in servaddr; memset(&servaddr,0,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5188); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); char sendbuf[1024] = {0}; char recvbuf[1024] = {0}; while(fgets(sendbuf,sizeof(sendbuf),stdin) != NULL) { int ret = sendto(sock,sendbuf,strlen(sendbuf),0,(struct sockaddr*)&servaddr,sizeof(servaddr)); recvfrom(sock,recvbuf,sizeof(recvbuf),0,NULL,NULL); fputs(recvbuf,stdout); memset(sendbuf,0,sizeof(sendbuf)); memset(recvbuf,0,sizeof(recvbuf)); } close(sock); } int main(void) { int sock; /*0表示内核自己选择协议*/ if ((sock = socket(PF_INET,SOCK_DGRAM,0)) < 0) ERR_EXIT("socket"); echo_cli(sock); return 0; }