函数select
select函数:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数:
- nfds:监控的文件描述符集里最大文件描述符加1,因为此参数会告诉内核检测前多少个文件文件描述符
- readfs:监控有读数据到达文件描述符集合,传入传出参数
- writefds:监控写数据到达文件描述符集合,传入传出参数
- exceptfds:监控异常发生到达文件描述符集合,如带外数据到达异常,传入传出参数
- timeout:定时阻塞监控时间。
void FD_CLR(int fd, fd_set *set); // 把文件描述符集里fd位清0 int FD_ISSET(int fd, fd_set *set); // 测试文件描述符集里fd是否置1 void FD_SET(int fd, fd_set *set); // 把文件描述符集合里fd位置1 void FD_ZERO(fd_set *set); // 把文件描述符集合里所有位清0
1. 测试代码:
- 服务端
1 //server.c 2 #include <unistd.h> 3 #include <stdio.h> 4 #include <string.h> 5 #include <netinet/in.h> 6 #include <arpa/inet.h> 7 #include <signal.h> 8 #include <sys/wait.h> 9 #include <ctype.h> 10 #include <unistd.h> 11 #include <sys/select.h> 12 #include "wrap.h" 13 14 #define SERV_PROT 6666 15 16 int main(int argc, char *argv[]) 17 { 18 int i, j, n, nread; 19 20 int maxfd = 0; 21 int listenfd, connfd; 22 char buf[BUFSIZ]; 23 24 struct sockaddr_in clie_addr, serv_addr; 25 socklen_t clie_addr_len; 26 listenfd = Socket(AF_INET, SOCK_STREAM, 0); 27 28 int opt = 1; 29 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 30 31 bzero(&serv_addr, sizeof(serv_addr)); 32 serv_addr.sin_family = AF_INET; 33 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 34 serv_addr.sin_port = htons(SERV_PROT); 35 Bind(listen, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 36 Listen(listenfd, 128); 37 38 fd_set rset, allset; 39 maxfd = listenfd; 40 FD_ZERO(&allset); 41 FD_SET(listenfd, &allset); 42 while (1) 43 { 44 rset = allset; 45 nread = select(maxfd + 1, &rset, NULL, NULL, NULL); //每次循环都从新设置select监控信号集 46 if(nread < 0) 47 perr_exit("select error"); 48 49 if (FD_ISSET(listenfd, &rset)) //说明有新的客户端连接请求 50 { 51 clie_addr_len = sizeof(clie_addr); 52 connfd = Accept(listenfd, (struct sockaddr *)&clie_addr, &clie_addr_len); 53 54 FD_SET(connfd, &allset); //向监控文件描述符集合allset添加新的文件描述符connfd 55 56 if (maxfd < connfd) 57 maxfd = connfd; 58 59 if (0 == --nread) //说明select只返回一个,并且listenfd,后续执行无须执行 60 continue; 61 } 62 for (i = listenfd + 1; i <= maxfd; i++) 63 { 64 if (FD_ISSET(i, &rset)) 65 { 66 if ((n = Read(i, buf, sizeof(buf))) == 0) //当client关闭链接时, 服务端也关闭对应链接 67 { 68 Close(i); 69 FD_CLR(i, &allset); //解除select对此文件描述符的监控 70 } 71 else if(n == -1) 72 perr_exit("read error"); 73 for (j = 0; j < n; ++j) 74 buf[j] = toupper(buf[j]); 75 Write(i, buf, n); 76 } 77 } 78 } 79 Close(listenfd); 80 return 0; 81 }
- 客户端
1 //client.c 2 #include <arpa/inet.h> 3 #include "wrap.h" 4 5 #define SERV_IP "192.168.245.139" 6 #define SERV_PORT 6666 7 8 int main(void) 9 { 10 int sfd, len; 11 struct sockaddr_in serv_addr; 12 char buf[BUFSIZ]; 13 sfd = Socket(AF_INET, SOCK_STREAM, 0); 14 bzero(&serv_addr, sizeof(serv_addr)); 15 serv_addr.sin_family = AF_INET; 16 inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr); 17 serv_addr.sin_port = htons(SERV_PORT); 18 Connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); 19 20 while (1) 21 { 22 fgets(buf, sizeof(buf), stdin); 23 int r = Write(sfd, buf, strlen(buf)); 24 printf("Write r ======== %d ", r); 25 len = Read(sfd, buf, sizeof(buf)); 26 printf("Read len ========= %d ", len); 27 Write(STDOUT_FILENO, buf, len); 28 } 29 Close(sfd); 30 return 0; 31 }
代码下载地址:链接
输出结果: