I/O多路转接之select服务器
来源:互联网 发布:什么是算法的复杂性 编辑:程序博客网 时间:2024/06/06 00:51
(1)每次调⽤用select,都需要把fd集合从⽤用户态拷贝到内核态,这个开销在fd很多时会很⼤大 (2)同时每次调⽤用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很⼤大 (3)select⽀支持的⽂文件描述符数量太⼩小了,默认是1024 select 服务器
发生了改变就是读事件写事件就绪
文件描述符通常关心读事件、写事件、异常事件
也可以关心至少一个或者有多个事件
select是系统调用接口
只负责等,一次等多个文件描述符就绪之后select就会返回通知上层
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select的参数:
nfds:等多个文件描述符中最大的加一
后四个参数都是输入输出型参数
输入型:哪些文件描述符关心对应类型的事件
输出型:哪些你所关心的文件描述符对应得事件已经发生了
rdset,wrset,exset分别对应于需要检测的可读⽂文件描述符的集合,可写⽂文件描述符的集 合及异 常⽂文件描述符的集合。
struct timeval结构⽤用于描述⼀一段时间长度,如果在这个时间内,需要监视的描述符没有事件 发⽣生则函数返回,返回值为0。
下⾯面的宏提供了处理这三种描述词组的⽅方式: FD_CLR(inr fd,fd_set* set);⽤用来清除描述词组set中相关fd 的位 FD_ISSET(int fd,fd_set *set);⽤用来测试描述词组set中相关fd 的位是否为真 FD_SET(int fd,fd_set*set);⽤用来设置描述词组set中相关fd的位 FD_ZERO(fd_set *set);⽤用来清除描述词组set的全部位 参数timeout为结构timeval,⽤用来设置select()的等待时间,其结构定义如下:
如果参数timeout设为: NULL:则表⽰示select()没有timeout,select将⼀一直被阻塞,直到某个⽂文件描述符上发⽣生了 事件。 0:仅检测描述符集合的状态,然后⽴立即返回,并不等待外部事件的发⽣生。 特定的时间值:如果在指定的时间段⾥里没有事件发⽣生,select将超时返回
函数返回值: 执行成功则返回文件描述词状态已改变的个数 如果返回0代表在描述词状态改变前已超过timeout时间,没有返回; 当有错误发⽣生时则返回-1,错误原因存于errno,此时参数readfds,writefds,exceptfds和 timeout的值变成不可预测。错误值可能为: EBADF ⽂文件描述词为⽆无效的或该⽂文件已关闭 EINTR 此调⽤用被信号所中断 EINVAL 参数n 为负值。 ENOMEM 核⼼心内存不⾜足 常见的程序⽚片段如下: fs_set readset; FD_SET(fd,&readset); select(fd+1,&readset,NULL,NULL,NULL); if(FD_ISSET(fd,readset)){…⋯…⋯}
理解select模型:
理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每⼀一bit 可以对应⼀一个⽂文件描述符fd。则1字节长的fd_set最⼤大可以对应8个fd。
(1)执⾏行fd_set set; FD_ZERO(&set);则set⽤用位表⽰示是0000,0000。
(2)若fd=5,执⾏行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)
(3)若再加⼊入fd=2,fd=1,则set变为0001,0011
(4)执⾏行select(6,&set,0,0,0)阻塞等待
(5)若fd=1,fd=2上都发⽣生可读事件,则select返回,此时set变为0000,0011。注意:没有事件 发⽣生的fd=5被清空。 基于上⾯面的讨论,可以轻松得出select模型的特点:
(1)可监控的文件描述符个数取决与sizeof(fd_set)的值。我这边服务 器上sizeof(fd_set)= 512,每bit表示一个⽂文件描述符,则我服务器上⽀支持的最⼤大⽂文件描述符是512*8=4096。据说 可调,另有说虽 然可调,但调整上限受于编译内核时的变量值。
(1)可以有效突破select可监控的⽂文件描述符上 限。
(2)将fd加⼊入select监控集的同时,还要再使⽤用一个数据结构array保存放到select监控集 中的fd,一是⽤用于再select 返回后,array作为源数据和fd_set进⾏行FD_ISSET判断。二是select 返回后会把以前加⼊入的但并无事件发⽣生的fd清空,则每次开始 select前都要重新从array取得fd 逐⼀一加入(FD_ZERO最先),扫描array的同时取得fd最⼤大值maxfd,⽤用于select的第⼀一个 参 数。
(3)可见select模型必须在select前循环array(加fd,取maxfd),select返回后循环array (FD_ISSET判断是否有时间发⽣生)。
#include<stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/types.h>#include <unistd.h>#include<arpa/inet.h>#include<netinet/in.h>#include<string.h>#include<unistd.h>#include<stdlib.h>int fds[sizeof(fd_set)*8]; static void Usage(char*proc){ printf("%s [local_ip] [local port]\n");}int startUp(char*ip,int port){ int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(2); } struct sockaddr_in server; server.sin_family=AF_INET; server.sin_port=htons(atoi(port)); server.sin_addr.s_addr=inet_addr(ip); if(bind(sock,(struct sockaddr*)&server,sizeof(struct sockaddr_in))<0) { perror("bind"); exit(3); } if(listen(sock,10)<0) { perror("listen"); exit(4); } return sock;}int main(int argv,char*argc[]){ if(argv!=3) { Usage(argc[0]); return 1; } int listen_sock=startUp(argc[1],argc[2]); int nums=sizeof(fd_set)*8; fd_set rds; int i=0; for(i=0;i<nums;i++) { fds[i]=-1; } while(1) { int max=-1; struct timeval timeout={5,0}; fds[0]=listen_sock; for(i=0;i<nums;i++) { if(fds[i]>-1) { FD_SET(fds[i],&rds);//在rdss设置所要关心的文件描述符对应的事件 } if(max<fds[i]) { max=fds[i]; } } switch(select(max+1,&rds,NULL,NULL,&timeout))// 执行成功则返回文件描述词状态已改变的个数 { case 0: printf("timeout...\n"); break; case -1: perror("select"); break; default: for(i=0;i<nums;i++) { if(i==0&&FD_ISSET(fds[i],&rds))//判断listen_sock描述符上对应的事件是否就绪 { struct sockaddr_in client; socklen_t len=sizeof(client); int newsock=accept(listen_sock,(struct socketaddr*)&client,&len);//继续取出将要关心的对应的文件描述符上的对应的事件 if(newsock<0) { perror("accept"); return 2; } else { int j=0; for(j=0;j<nums;j++) { if(fds[j]==-1) { break; } } if(j==nums) { close(newsock); } else { fds[j]=newsock;//将新的所要关心的文件描述符对应的事件放到fds合适的位置 } } } else if(i!=0&&FD_ISSET(fds[i],&rds))//如果不是监听套接字但是是其他文件描述符对应的读事件就绪了 { char buf[1024]; ssize_t s=read(fds[i],buf,sizeof(buf)-1); if(s>0) { printf("client say:%s\n",buf); } else if(s==0) { printf("client quit!\n"); close(fds[i]); fds[i]=-1; } else { perror("read"); close(fds[i]); fds[i]=-1; } } } } } return 0;}
(1)每次调⽤用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大 ’
(3)select⽀支持的⽂文件描述符数量太小了,默认是1024
- 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
- I/O多路转接之select
- I/O多路转接之select
- I/O多路转接----select的服务器实现
- 实现多路转接I/O——select服务器
- Linux【网络编程】——I/O多路转接之Select服务器
- Linux下高级I/O多路转接之select服务器
- JS限制input输入的为数字并且有小数的时候最多保留两位小数
- win7删除桌面右键菜单项
- 例题:二维数组打印六阶杨辉三角
- JNI中参数的传递与操作(下)
- HDU 6058 Kanade's sum 逆序求第k大
- I/O多路转接之select服务器
- JQuery点击锚点滚动到相应的模块
- DES 加密解密
- 多核cpu通信的相关寄存器
- 安装raw文件下的apk文件
- HandBrake 开源视频转码器、编码转换器、格式转换器
- redis 安装启动及设置密码<windows>
- openstack虚拟机迁移操作
- 作为技术人员的死对头,其实我也很苦逼