本文共 5621 字,大约阅读时间需要 18 分钟。
https://blog.csdn.net/men_wen/article/details/53456435
select函数能够告知内核对哪些描述符(不局限于套接字)感兴趣以及等待多长事件
#include#include #include int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);//返回值:返回就绪描述符数目,若超时则为0, 若出错则为-1
struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microseconds */};//当timeout为NULL,则永远等待。//当timeout为timeval,等待固定时间。//当timeout为timeval,但timeval时间设置为0,则检查描述符字立即返回,称为轮询。
#define __FD_SETSIZE 1024typedef struct { unsigned long fds_bits[__FD_SETSIZE / (8 * sizeof(long))];} __kernel_fd_set;
select函数使用描述符集,通常是一个整数数组,其中每一个整数中的每一位对应一个描述符。如何操作这些描述符则系统提供了四个宏
void FD_CLR(int fd, fd_set *set);//把文件描述符集合里fd清零int FD_ISSET(int fd, fd_set *set);//测试文件描述符集合里fd是否置1void FD_SET(int fd, fd_set *set);//把文件描述符集合里fd位置1void FD_ZERO(fd_set *set);//把文件描述符集合里所有位清0
#include "wrap.h"#define MAXLINE 1024int start_ser(char *ipaddr, char *port){ int sock = Socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in serveraddr; bzero(&serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(atoi(port)); inet_pton(AF_INET, ipaddr, &serveraddr.sin_addr); Bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); Listen(sock, 128); return sock;}int main(int argc, char *argv[]){ int i, maxi, maxfd, listenfd, connfd, sockfd; int nready, client[FD_SETSIZE]; ssize_t n; fd_set readset, allset; char buf[MAXLINE]; socklen_t clilen; struct sockaddr_in clientaddr; listenfd = start_ser(argv[1], argv[2]); //监听文件描述符 maxfd = listenfd;//最大的文件描述符 maxi = -1;//数组中最大文件描述符下标 for(i = 0; i < FD_SETSIZE; i++){ client[i] = -1; } FD_ZERO(&allset);//初始化allset集合 FD_SET(listenfd, &allset);//添加监听文件描述符到集合allset中 while(1){ readset = allset;//每次select都要初始化集合,结构体可以直接赋值 nready = select(maxfd+1, &readset, NULL, NULL, NULL);//组摄等待连接或请求 if(FD_ISSET(listenfd, &readset)){ //当监听文件描述符相应有新的客户端连接时 clilen = sizeof(clientaddr); connfd = Accept(listenfd, (struct sockaddr *)&clientaddr, &clilen);//接收该客户端 if(connfd < 0){ perr_exit("accept err"); break; } for(i = 0; i < FD_SETSIZE; i++){ if(client[i] < 0){ client[i] = connfd; //保存文件描述符到数组 break; } } if(i == FD_SETSIZE){ //连接个数不能大于内核规定的FD_SETSIZE perr_exit("too many clients"); } FD_SET(connfd, &allset);//添加新描述符到allset集合中 if(connfd > maxfd){ maxfd = connfd; //更新最大文件描述符 } if(i > maxi){ maxi = i; //更新最大文件描述符下标 } if(--nready == 0){ //只有一个listenfd响应则直接跳过下面的语句 continue; } } for(i = 0; i <= maxi; i++){ //处理已连接客户端的请求 if((sockfd = client[i]) < 0){ continue; } if(FD_ISSET(sockfd, &readset)){ //sockfd是否在readset集合中 memset(buf, '\0', MAXLINE); if((n = Read(sockfd, buf, MAXLINE-1)) == 0){ Close(sockfd); FD_CLR(sockfd, &allset); client[i] = -1; }else{ printf("client:%s\n", buf); } if(--nready == 0){ //判断是否查找完 break; } } } } return 0;}
#include "wrap.h"int main(int argc, char *argv[]){ int connfd; struct sockaddr_in serveraddr; char buf[1024]; connfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(atoi(argv[2])); inet_pton(AF_INET, argv[1], &serveraddr.sin_addr); Connect(connfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); while(fgets(buf, 1024, stdin) != NULL){ Write(connfd, buf, strlen(buf)); } Close(connfd); return 0;}