目录
UDP客户端服务端模型
数据传输
发送数据
#include <sys/socket.h> ssize_t send(int sockfd, const void *buf, size_t nbytes, int flag);
- 返回: 成功返回发送字节数,出错返回-1。
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flag);
- 返回: 成功返回发送字节数,出错返回-1。
ssize_t sendto(int sockfd, const void *buf, size_t nbytes, int flag, const struct sockaddr *destaddr, socklen_t destlen);
- 返回: 成功返回发送字节数,出错返回-1。
struct msghdr{ void *msg_name; /*optional address*/ socklen_t msg_namelen; /*address size in bytes*/ struct iovec *msg_iov; /*array of I/O buffers*/ int msg_iovlen; /*number of elements in array */ void *msg_control; /*ancillary data*/ socklen_t msg_controllen; /*number of ancillary bytes*/ int msg_flags; /*flags for received message*/ }
接受数据
#include <sys/socket.h> ssize_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);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flag);
- 返回: 返回消息的字节数,无消息返回0,出错返回-1
服务端程序代码
int sockfd; void sig_handler(int signo) { if(signo==SIGINT) { printf("server close\n"); close(sockfd); exit(1); } } //输出客户端的信息 void out_addr(struct sockaddr_in* clientaddr) { char ip[16]; memset(ip,0,sizeof(ip)); inet_ntop(AF_INET, &clientaddr->sin_addr.s_addr,ip, sizeof(ip)); int port=ntohs(clientaddr->sin_port); printf("client:%s(%d)\n", ip, port); } //和客户端进行通信 void do_service(int fd) { struct sockaddr_in clientaddr; socklen_t len = sizeof(clientaddr); char buffer[1024]; memset(buffer, 0, sizeof(buffer)); //接受客户端的数据报文 if(recvfrom(sockfd,buffer, sizeof(buffer), 0, (struct sockaddr*)&clientaddr, &len)<0) { perror("recvfrom error"); } else { out_addr(&clientaddr); printf("client send info:%s\n", buffer); //向客户端发送数据报文 long int t =time(0); char*ptr = ctime(&t); size_t size = strlen(ptr)*sizeof(char); if(sendto(sockfd, ptr, size, 0, \ (struct sockaddr*)&clientaddr, len)<0) { perror("sendto error"); } } } int main(int argc, char *argv[]) { if(argc<2) { printf("usage:%s port\n",argv[0]); exit(1); } if(signal(SIGINT, sig_ handler) == SIG_ERR) { perror("signal sigint error"); exit(1); } /*步骤1:创建 socket*/ sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) { perror("socket error"); exit(1); } int ret; int opt=1; //设置套接字选项 if((ret=setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, \ sizeof(opt)))<0) { perror("setsockopt error"); exit(1); } /*步骤2:调用bind函数对socket和地址进行绑定*/ struct sockaddr_in serveraddr; memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET;//IPV4 serveraddr.sin_port = htons(atoi(argv[1]));//port serveraddr.sin_addr.s_addr = INADDR_ANY;//ip if(bind(sockfd, (struct sockaddr*)&serveraddr, \ sizeof(serveraddr))<0) { perror("bind error"); exit(1); } /*步骤3:和客户端进行双向的数据通信*/ while(1){ do_service(); return 0; } }
客户端程序代码
int main(int argc,char *argv[]) { if(argc < 3) { printf("usage:%s ip port\n", argv[0]); exit(1); } /*步骤1:创建 socket*/ sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) { perror("socket error"); exit(1); } /*步骤2:调用recvfrom和sendto等函数 *和服务器端双向通信 */ struct sockaddr_in serveraddr; memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET;//IPV4 serveraddr.sin_port = htons(atoi(argv[1]));//port serveraddr.sin_addr.s_addr = INADDR_ANY;//ip if(connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) { perror("connect error"); exit(1); } char buffer[1024] = "Hello world!"; //向服务器端发送数据报文 //if(sendto(sockfd, buffer, sizeof(buffer), 0,\ // (struct sockaddr*)&serveraddr,sizeof(serveraddr)) < 0) if(sendto(sockfd, buffer, sizeof(buffer), 0) < 0) { perror("sendto error"); exit(1); } else { //接受服务器端发送的数据报文 memset(buffer, 0, sizeof(buffer)); size_t size; if(recv(sockfd, buffer, sizeof(buffer), 0) <0 ) { perror("recv error"); exit(1); } else { printf("%s",buffer); } } close(sockfd); return 0; }
广播
- SO_BROADCAST 选项控制着UDP套接字是否能够发送广播数据报,选项的类型为int,非零意味着“是”,注意,只有UDP套接字可以使用这个选项,TCP是不能使用广播的。
int opt = 1; if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ //错误处理 } if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) < 0) { //错误处理 }
广播之接受者
int sockfd; void sig_handler(int signo) { if(signo==SIGINT) { printf("server close\n"); close(sockfd); exit(1); } } int main(int argc, char *argv[]) { if(argc<2) { printf("usage:%s port\n",argv[0]); exit(1); } if(signal(SIGINT, sig_handler) == SIG_ERR) { perror("signal sigint error"); exit(1); } /*步骤1:创建 socket*/ sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) { perror("socket error"); exit(1); } /*步骤2:调用bind函数对socket和地址进行绑定*/ struct sockaddr_in serveraddr; memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET;//IPV4 serveraddr.sin_port = htons(atoi(argv[1]));//port serveraddr.sin_addr.s_addr = INADDR_ANY;//ip if(bind(sockfd, (struct sockaddr*)&serveraddr, \ sizeof(serveraddr))<0) { perror("bind error"); exit(1); } char buffer[1024]; struct sockaddr_in clientaddr; socklen_t len=sizeof(clientaddr); while(1){ memset(buffer, 0, sizeof(buffer)); memset(&clientaddr, 0, sizeof(clientaddr)); if(recvfrom(sockfd, buffer, sizeof(buffer),0,\ (struct sockaddr*)&clientaddr, &len)<0) { perror("recvfrom error"); exit(1); } else { char ip[16]; inet_ntop(AF_INET, &clentaddr.sin_addr.s_addr, ip, sizeof(ip)); int port=ntohs(clientaddr.sin_port); printf("%s(%d):%s\n", ip, port, buffer); } } close(sockfd); return 0; }
广播之发送者
int sockfd; int main(int argc, char *argv[]) { if(argc<2) { printf("usage:%s port\n", argv[0]); exit(1); } /*步骤1:创建 socket*/ sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) { perror("socket error"); exit(1); } int opt=1;//采用广播方式发送 setsockopt(sockfd, SOL_SOCKET,SO_BROADCAST, &opt, sizeof(opt)); struct sockaddr_in serveraddr; memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin family=AF_INET; serveraddr.sin_port = htons(atoi(argv[2])); inet_pton(AF_INET, argv[1], &serveraddr.sin_addr.s_addr); printf("I will broadcast...\n"); char * info="hello iotek"; size_t size=strlen(info)* sizeof(char); if(sendto(sockfd, info, size,0, (struct sockaddr*)&serveraddr, sizeof(serveraddr))<0) { perror("sendto error"); exit(1); } else { printf("boradcast success\n"); } close(sockfd); return 0; }