select
#include <sys/select.h> void FD_CLR(int fd, fd_set *set); int FD_ISSET(int fd, fd_set *set); void FD_SET(int fd, fd_set *set); void FD_ZERO(fd_set *set); int select(int nfds, fd_set *readfds, fd_set * writefds, fd_set *exceptfds, struct timeval *timeout); int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask); struct timeval{ long tv_sec; long tv_usec; };` struct timespec { long tv_sec; long tv_nsec; };
同时监听多个阻塞的文件描述符(如多个网络连接),任一文件有数据就返回。
nfds;所关心的最大fd+1.
readfs:传入:关心的可读文件;传出:实际可读文件。
timeout:1)NULL死等;2)tv_sec=0,tv_usec=0,立即返回,0s,不等;3)tv_sec=n,tv_usec=m;有限等。
失败:-1;无设备可用:0;有设备可用,返回正数,所有可读fd数目之和。
注: Some code calls select() with all three sets empty, nfds zero, and a non-NULL timeout as a fairly portable way to sleep with subsecond precision.
可读:1)有数据;2)关闭连接;3)有新的连接请求(监听socketfd)。
可写:1)无流量控制;2)关闭连接。
异常:1)收到紧急数据。
代码示例:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <ctype.h> #include <netinet/in.h> #include <arpa/inet.h> #define MAXLINE 80 #define SERV_PORT 2000 int main(void) { int i, maxi, maxfd, listenfd, connfd, sockfd, ret; int nready, client[FD_SETSIZE]; ssize_t n; fd_set rset, allset; char buf[MAXLINE]; char str[INET_ADDRSTRLEN]; socklen_t cliaddr_len; struct sockaddr_in cliaddr, servaddr; listenfd = socket(AF_INET, SOCK_STREAM, 0); if(listenfd < 0) { perror("listen"); return -1; } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); ret = bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); if(ret < 0) { perror("bind"); return -1; } listen(listenfd, 10); maxfd = listenfd; maxi = -1; for(i = 0; i < FD_SETSIZE; i++) client[i] = -1; FD_ZERO(&allset); FD_SET(listenfd, &allset); while(1){ rset = allset; nready = select(maxfd+1, &rset, NULL, NULL, NULL); if(nready < 0){ perror("select"); exit(EXIT_FAILURE); } if(FD_ISSET(listenfd, &rset)) { cliaddr_len = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); if(connfd < 0){ perror("accept"); exit(EXIT_FAILURE); } printf("received from %s at port %d ", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port)); for(i = 0; i < FD_SETSIZE; i++) { if(client[i] < 0) { client[i] = connfd; break; } } if(i == FD_SETSIZE) { //efputs("too many clients. "); printf("too many clients. "); exit(EXIT_FAILURE); } FD_SET(connfd, &allset); if(connfd >maxfd) { maxfd = connfd; } if(i > maxi) maxi = i; if(--nready == 0) continue; } for(i = 0; i<= maxi; i++) { if((sockfd = client[i]) < 0) continue; if(FD_ISSET(sockfd, &rset)) { if((n = read(sockfd, buf, MAXLINE)) == 0) { close(sockfd); FD_CLR(sockfd, &allset); client[i] = -1; } else { int j; for(j = 0; j < n; j++) buf[j] = toupper(buf[j]); write(sockfd, buf, n); } if(--nready == 0) break; } } } }
参考: