# select
/* select阻塞函数,多次还是需要while,在新建客户端方面有没有都一样 因为accept多次也需要while 但在判断客户端是否有数据到来方面 使用了select就不需要创建多个线程或进程判断了,select可以批量判断 */ #include <stdio.h> #include <sys/select.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <unistd.h> int main() { int lfd = socket(AF_INET, SOCK_STREAM, 0); if(lfd == -1) { perror("socket"); exit(-1); } char *buf = "192.168.248.128"; int ip; inet_pton(AF_INET, buf, &ip); struct sockaddr_in saddr; saddr.sin_addr.s_addr = ip; saddr.sin_port = htons(9999); saddr.sin_family = AF_INET; // 绑定 int ret = bind(lfd, (struct sockaddr *) &saddr, sizeof(saddr)); if(ret == -1) { perror("bind"); exit(-1); } ret = listen(lfd, 5); if(ret == -1) { perror("listen"); exit(-1); } fd_set readfds, tmp; // 因为select返回时,内核会修改set,为了能够实现多次监听,需要一个副本记录原始set FD_ZERO(&readfds); FD_SET(lfd, &readfds); int maxfd = lfd; // 需要监听的最大序号的描述符 while(1) { tmp = readfds; ret = select(maxfd + 1, &tmp, NULL, NULL, NULL); if(ret == -1) { perror("select"); exit(-1); } else if(ret == 0) { continue; } else { if(FD_ISSET(lfd, &tmp)) // 是否有新的客户端到达 { struct sockadd_in client_addr; int client_addr_len = sizeof(client_addr); int cfd = accept(lfd, (struct sockaddr *) &client_addr, &client_addr_len); FD_SET(cfd, &readfds); maxfd = cfd > maxfd ? cfd : maxfd; } for(int i = lfd + 1; i < maxfd + 1; i++) // 已经到达的客户端是否写了数据到我的读缓冲区 { if(FD_ISSET(i, &tmp)) // 如果我的读缓冲区有数据 { char readBuf[1024]; int read_len = read(i, readBuf, sizeof(readBuf)); // 读取数据 if(read_len == 0) { printf("客户端连接断开······"); close(i); // 既然关闭了连接,则close描述符 FD_CLR(i, &readfds); // 在监听集合中删除相应描述符 } else if(read_len == -1) { perror("read"); exit(-1); } else { printf("recv info : %s\n", readBuf); write(i, readBuf, strlen(readBuf) + 1); } } } } } close(lfd); return 0; }
# poll
#include <stdio.h> #include <sys/select.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <poll.h> int main() { int lfd = socket(AF_INET, SOCK_STREAM, 0); if(lfd == -1) { perror("socket"); exit(-1); } char *buf = "192.168.248.128"; int ip; inet_pton(AF_INET, buf, &ip); struct sockaddr_in saddr; saddr.sin_addr.s_addr = ip; saddr.sin_port = htons(9999); saddr.sin_family = AF_INET; // 绑定 int ret = bind(lfd, (struct sockaddr *) &saddr, sizeof(saddr)); if(ret == -1) { perror("bind"); exit(-1); } ret = listen(lfd, 5); if(ret == -1) { perror("listen"); exit(-1); } struct pollfd fds[1024]; // poll 是通过结构体数组 for(int i = 0; i < 1024; i++) { fds[i].fd = -1; fds[i].events = POLLIN; } int cnt = 0; while(1) { ret = poll(fd, cnt + 1, -1); if(ret == -1) { perror("poll"); exit(-1); } else if(ret == 0) { continue; } else { if(fds[0].revents & POLLIN) // 是否有新的客户端到达,用&是因为防止revents是多个状态的| { struct sockadd_in client_addr; int client_addr_len = sizeof(client_addr); int cfd = accept(lfd, (struct sockaddr *) &client_addr, &client_addr_len); int i; for(i = 1; i < 1024 && fds[i].fd != -1; i++); fds[i].fd = cfd; fds[i].events = POLLIN; cnt = i > cnt ? i : cnt; } for(int i = 0; i < cnt + 1; i++) // 已经到达的客户端是否写了数据到我的读缓冲区 { if(fds[i].revents & POLLIN) // 如果我的读缓冲区有数据 { char readBuf[1024]; int read_len = read(i, readBuf, sizeof(readBuf)); // 读取数据 if(read_len == 0) { printf("客户端连接断开······"); close(i); // 既然关闭了连接,则close描述符 FD_CLR(i, &readfds); // 在监听集合中删除相应描述符 } else if(read_len == -1) { perror("read"); exit(-1); } else { printf("recv info : %s\n", readBuf); write(i, readBuf, strlen(readBuf) + 1); } } } } } close(lfd); return 0; }
# epoll
标签:lfd,include,addr,epoll,int,ret,saddr,poll,select From: https://www.cnblogs.com/WTSRUVF/p/17399993.html