I/O多路转接(一)——select函数
来源:互联网 发布:vender软件 编辑:程序博客网 时间:2024/06/06 02:51
I/O多路转接(一)——select函数
I/O的过程可以分成两步,等待和数据搬迁。
等待的过程等的是,读写事件就绪,比如说缓冲区有数据了说明读事件就绪,空了则说明写事件就绪。I/O的多路转接可以同时等待多个文件描述符,大大节省了I/O的等待时间,从而提高I/O效率。
多路转接函数要做的工作就是等待,等待读写或者异常事件就绪后通知用户。
第一篇介绍的是select函数。
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
返回值
大于0,有多少fd就绪;等于0,超出等待时间却没有一个fd就绪;小于0,出错。
参数
nfds:需要select等待的file descriptor数量。
readfds,writefds,exceptfds:分别代表了读事件集,写事件集,异常事件集。
timeout:代表了愿意等待的时间,timeout==NULL代表永远等待;timeout->tv_sec,
timeout->tv_usec分别代表秒与微妙,都等于0代表不等待检测后直接返回;不等于0代表愿意等待吃的时间。
对于读写异常事件集,用专门的操作函数。
void FD_CLR(int fd, fd_set *set);//清理一个fd
int FD_ISSET(int fd, fd_set *set);//检测一个fd是否就绪
void FD_SET(int fd, fd_set *set);//添加一个fd到set,代表你想关心哪个fd的哪个事件
void FD_ZERO(fd_set *set);//初始化
Select缺点
- select等待的file descriptor的数量是有上线的,默认为1024。
- 调用select时,需要将fd_array集合从用户态拷贝到内核态,同时也要在内核态中遍历所有传进来的fd。
- 由于三个事件集参数均是输入输出型参数,用户需要自己维护一个fd_array集合用来保存想要等待的file descriptor的事件,每次调用select前需要重新设置三个事件集,调用结束后又需要遍历检测 。
- 当select所等待的fd数量越来越多时,2与3的开销会越来越大,服务器的性能也随之越来越差。
下面是使用select编写的简单网路服务器
为了简单快速使用select这里只关心读事件。
server.c
#include<stdio.h>#include<sys/types.h>#include<sys/socket.h>#include<sys/stat.h>#include<stdlib.h>#include<string.h>#include<netinet/in.h>#include<arpa/inet.h>#include<unistd.h>int startup(char*ip,int port){ int sock = socket(AF_INET,SOCK_STREAM,0); if(sock < 0){ perror("socket"); return 2; } struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons(port); local.sin_addr.s_addr = inet_addr(ip); if(bind(sock,(struct sockaddr*)&local,sizeof(local)) < 0){ perror("bind"); return 3; } if(listen(sock,10) < 0){ perror("listen"); return 4; } return sock;}int main(int argc,char *argv[]){ if(argc!= 3){ printf("Usage:%s [ip] [port]\n",argv[0]); return 1; } int listen_sock = startup(argv[1],atoi(argv[2])); printf("listen_sock has been created,the value is %di\n",listen_sock); //监听套接字创建完成,等待读事件发生。 fd_set rfds;//读事件描述副集。 int size = sizeof(rfds)*8; int fd_array[size];//创建一个保存所有关心描述符的数组。 int i = 0; for(;i<size;i++ ){//初始化数组。 fd_array[i] = -1; } fd_array[0] = listen_sock;//数组第一个位置永远保存监听套接字描述符。 struct timeval timeout = {5,1}; while(1){ int max = -1; FD_ZERO(&rfds);//清空读事件描述符集。 for(i = 0;i < size; i++ ){ FD_SET(fd_array[i],&rfds);//将想要关心的读时间描述符添加 //到读事件描述符集。 if(max < fd_array[i]) max = fd_array[i];//找出最大的描述符 } //设置读事件描述符集完成,开始调用select进行等待 int ret = select(max + 1,&rfds,NULL,NULL,NULL/*&timeout*/); switch(ret){ case 0: printf("timeout\n"); break; case -1: perror("select"); break; default: { //一一查看所关心的读事件描述符是否发生状态改变 for(i= 0;i < size;i++){ if(fd_array[i] < 0) continue; if(i==0&&FD_ISSET(fd_array[i],&rfds)){ //listen_sock描述符状态改变说明有client请求连接 struct sockaddr_in client; socklen_t len = sizeof(client); int new_sock = accept(listen_sock,(struct sockaddr*)&client,&len); if(new_sock < 0){ perror("accept"); continue; }else{ printf("get a client!ip:%s,port:%d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port)); for(i= 0;i<size;i++){//找到一个未被占用的位置存放新链接的描述符。 if(fd_array[i]< 0){ fd_array[i]= new_sock; break; } } if(i==size){ close(new_sock); printf("server is full\n"); } } }else if(i!= 0&&FD_ISSET(fd_array[i],&rfds)){//其他关心描述符状态改变。 char buf[1024]; ssize_t s = read(fd_array[i],buf,sizeof(buf)-1); if(s >0){ buf[s]= 0; printf("client say# %s\n",buf); }else if(s==0){ printf("client is quit!\n"); close(fd_array[i]); fd_array[i]= -1; }else{ perror("read"); close(fd_array[i]); fd_array[i]= -1; } } } } break; } } return 0;}
- I/O多路转接(一)——select函数
- i/o多路转接 select(一)
- 实现多路转接I/O——select服务器
- linux—I/O多路转接之select
- select函数与I/O多路转接
- select函数与I/O多路转接
- select函数与I/O多路转接
- Linux 多路转接I/O select函数
- UNIX环境高级编程——I/O多路转接(select、pselect和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
- 【Linux】I/O多路转接select
- 人脸检测--【代码过程,错误记录】
- Hook匹配过程----之一
- BZOJ 1409 快速幂+欧拉定理
- JAVA之outofmemory
- linux文本处理三剑客之grep
- I/O多路转接(一)——select函数
- OpenCV中的findContours函数参数详解
- centos7 关机指令
- HDU2896[病毒侵袭] AC自动机
- 页面实现图片传输放大预览JS
- 工作-2017.07.30-周记总结篇(一)
- centos的/etc/rc.d下的rc.local没有生效的问题
- 各种排序之间的比较和实现
- C语言中使用静态函数的好处