Unix系统编程(6) - I/O多路复用之select
来源:互联网 发布:java编译器中文安卓版 编辑:程序博客网 时间:2024/05/17 01:13
1. I/O多路复用基本思路
I/O多路复用就是让应用程序可以同时对多个I/O端口进行监控以判断其上的操作是否可以进行,达到时间复用的目的。由于I/O多路复用是在单一进程的上下文中的,因此每个逻辑流程都能访问该进程的全部地址空间,所以开销比多进程低得多。由于I/O多路复用都是在单一进程中进行的,所以不会出现多线程中的线程不安全的问题。
2. select模型
在man page中给出的select函数原型:
/* According to POSIX.1-2001 */ #include <sys/select.h> /* According to earlier standards */ #include <sys/time.h> #include <sys/types.h> #include <unistd.h> int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 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); #include <sys/select.h> int pselect(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, const struct timespec *timeout,const sigset_t *sigmask);
函数准许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经历一段指定的时间后才唤醒。man page中给出了一个较新的函数pselect,这个函数仅仅是多了一个sigmask参数。sigmask参数指定了在执行pselect函数时屏蔽的信号集合。
select()函数参数:
int nfds, //监控的文件描述符集里最大文件描述符加1fd_set *readfds, //监控有读数据到达文件描述符集合fd_set *writefds,//监控有写数据到达文件描述符集合fd_set *exceptfds,//监控异常发生达文件描述符集合,如带外数据到达异常,传入传出参数struct timeval *timeout //定时阻塞监控时间,3种情况/*1.NULL,永远等下去2.设置timeval,等待固定时间3.设置timeval里时间均为0,检查描述字后立即返回,轮询*/
另外的三个函数功能比较简单:
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
3. select模型回射服务器
#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <string.h>#include <arpa/inet.h>#include <pthread.h>#include <sys/time.h>#include <sys/select.h>#define SERV_PORT 8000#define MAXLINE 1024int main(){ //maxfd: 打开的最大文件描述符标号 //listenfd: 监听描述符 //confd: 链接描述符 //clientaddrlen 客户端地址长度 //sockfd: 暂存量 int maxfd, listenfd, confd, clientaddrlen, sockfd, n, i = 0; struct sockaddr_in serveraddr, clientaddr; //服务器端地址,客户端地址 char str[INET_ADDRSTRLEN]; //存放IP地址,点分十进制表示 fd_set rset, allset; //select 使用 char buf[MAXLINE]; //传输数据 int nReady, client[FD_SETSIZE], maxi; // //1. 创建一个socket listenfd = socket(AF_INET, SOCK_STREAM, 0); //2. 绑定一个端口 bzero(&serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(SERV_PORT); serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(listenfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)); //3. 设置监听 listen(listenfd, 20); maxfd = listenfd; maxi = 0; for(i=0; i<FD_SETSIZE; ++i); //初始化clinet[] client[i] = -1; FD_ZERO(&allset); //select监控文件描述符集 FD_SET(listenfd, &allset); for(;;) { rset = allset; nReady = select(maxfd + 1, &rset, NULL, NULL, NULL); if(nReady < 0) //select出错 { perror("select err\n"); break; } if(FD_ISSET(listenfd, &rset)) //新链接的客户端 { clientaddrlen = sizeof(clientaddr); confd = accept(listenfd, (struct sockaddr *)&clientaddr, &clientaddrlen); printf("ip: %s, port: %d \n", inet_ntop(AF_INET, &clientaddr.sin_addr, str, sizeof(str)), ntohs(clientaddr.sin_port)); for(i=0; i<FD_SETSIZE; ++i) { if(client[i] < 0) { client[i] = confd; break; } } if(i == FD_SETSIZE) { fputs("limited\n", stderr); exit(1); } FD_SET(confd, &allset); if(confd > maxfd) maxfd = confd; 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]=0; } else write(sockfd, buf, n); if(--nReady == 0) break; } } } close(listenfd); return 0;}
测试用客户端代码,可使用上一篇博文中的客户端。
1 0
- Unix系统编程(6) - I/O多路复用之select
- Unix系统编程(7) - I/O多路复用之poll
- I/O多路复用之select系统调用
- I/O多路复用之select
- I/O 多路复用之select
- I/O多路复用之select
- I/O多路复用之select
- I/O多路复用之select
- I/O多路复用之select
- I/O多路复用之select
- I/O多路复用之select
- I/O多路复用之select
- I/O多路复用之select
- I/O 多路复用之select
- Unix系统编程(8) - I/O多路复用之epoll(Linux)
- Linux网络编程---I/O多路复用 之 select
- socket编程:多路复用I/O服务端客户端之select
- 嵌入式linux网络编程之I/O多路复用select
- 前台页面向后台提交中文出现乱码解决办法
- hdu3506Monkey Party
- java之构造函数
- CAP原理和BASE思想
- JAVA实现单链表的增删改查
- Unix系统编程(6) - I/O多路复用之select
- setjmp与longjmp使用(转载)
- [javascript权威指南][阅读笔记]八
- Python 点球小游戏
- hdu 5673 卡特兰数,逆元
- iOS设计模式(03):工厂方法
- 整型字符常量和字符字面量的区别 sizeof(char) 和 sizeof('a')
- 晏浩洋
- 数组_01