1.I/O的操作方式
(1)阻塞等待
(2)解决办法
2.I/O口多路转换技术:
(1)先构造一张有关于文件描述符的列表,将要监听的文件描述符加入到其中
(2)调用一个函数,监听该表中的文件描述符,然后看表中哪一个文件描述符在进行I/O端口的操作,该函数才返回。该函数是阻塞函数,需要调用部分内存实现
3.I/O口多路转换---select
(2)文件描述符操作函数
●全部清空
void FD_ZERO(fd_set *set);
●删除其中的一项
void FD_CLR(int fd,fd_set *set);
●将某个文件描述符加到集合里面
void FD_SET(int fd,fd_set *set);
●判断某个文件描述符是否在集合里
void FD_ISSET(int fd,fd_set *set);
3.select函数的实例:
/*服务端*/
#include <sys/time.h> #include <sys/types.h> #include <unistd.h> #include<stdio.h> #include<stdlib.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #define MAXLINE 80 #define SERV_PORT 8000 int main(int argc, char *argv[]){ int i, maxi, maxfd, listenfd, connfd, sockfd; //client 自定义数组,遍历上限值 int nready, client[FD_SETSIZE]; /* FD_SETSIZE 默认为 1024 */ ssize_t n; //用到的集合,暂存的作用 fd_set rset, allset;//保存原来的样子 char buf[MAXLINE]; char str[INET_ADDRSTRLEN]; /* #define INET_ADDRSTRLEN 16 */ socklen_t cliaddr_len; struct sockaddr_in cliaddr, servaddr; listenfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); Listen(listenfd, 20); /* 默认最大128 */ maxfd = listenfd; /* 初始化 */ maxi = -1; /* client[]的下标 */ for (i = 0; i < FD_SETSIZE; i++) client[i] = -1; /* 用-1初始化client[] */ FD_ZERO(&allset); FD_SET(listenfd, &allset); /* 构造select监控文件描述符集 */ ///////////////////////描述是否有客户端连接 for ( ; ; ) { //rect 是 rset = allset; /* 每次循环时都从新设置select监控信号集 */ nready = select(maxfd+1, &rset, NULL, NULL, NULL); if (nready < 0) perr_exit("select error"); //是哪个要连接 if (FD_ISSET(listenfd, &rset)) { /* new client connection */ cliaddr_len = sizeof(cliaddr); connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);//直接调用accpet,不会堵塞 printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port)); //监听的时候加到自定义的集合中去,找到任意一个为-1的塞进去 for (i = 0; i < FD_SETSIZE; i++) if (client[i] < 0) { client[i] = connfd; /* 保存accept返回的文件描述符到client[]里 */ break; } /* 达到select能监控的文件个数上限 1024 */ if (i == FD_SETSIZE) { fputs("too many clients\n", stderr); exit(1); } FD_SET(connfd, &allset); /* 添加一个新的文件描述符到监控信号集里 */ if (connfd > maxfd) maxfd = connfd; /* select第一个参数需要 */ if (i > maxi) maxi = i; /* 更新client[]最大下标值 ,判断数组是否满了*/ if (--nready == 0)//设置返回出来的总数 continue; /* 如果没有更多的就绪文件描述符继续回到上面select阻塞监听,负责处理未 处理完的就绪文件描述符 */ } ////////////////////////读数据用的 for (i = 0; i <= maxi; i++) { /* 检测哪个clients 有数据就绪 */ if ( (sockfd = client[i]) < 0)//判断是否赋值成功 continue; if (FD_ISSET(sockfd, &rset)) { if ( (n = Read(sockfd, buf, MAXLINE)) == 0) { /* 当client关闭链接时,服务器端也关闭对应链接 */ Close(sockfd); FD_CLR(sockfd, &allset); /* 解除select监控此文件描述符 */ 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; } } } close(listenfd); return 0; }
/*客户端*/
#include <sys/time.h> #include <sys/types.h> #include <unistd.h> #include<stdio.h> #include<stdlib.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #define MAXLINE 80 #define SERV_PORT 8000 int main(int argc, char *argv[]) { struct sockaddr_in servaddr; char buf[MAXLINE]; int sockfd, n; sockfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr); servaddr.sin_port = htons(SERV_PORT); Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); while (fgets(buf, MAXLINE, stdin) != NULL) { Write(sockfd, buf, strlen(buf)); n = Read(sockfd, buf, MAXLINE); if (n == 0) printf("the other side has been closed.\n"); else Write(STDOUT_FILENO, buf, n); } Close(sockfd); return 0; }
运行结果:
原文:https://www.cnblogs.com/ylq0824/p/10883854.html