I/O复用----select
2018-07-31 (星期二)
I/O复用:
一个应用程序通常需要服务一个以上的文件描述符.
例如stdin,stdout,进程间通信以及若干文件进行I/O,如果不借助线程的话,(线程通常在同一时间无法服务一个以上文件描述符),就是分开每个所要服务的文件描述符,这样做有个问题,就是一旦遇到一个没有准备好的文件描述符,进程就会受阻,可能只受阻几秒,但是用户体验就会大大下降.借助线程,那么进程要维护额外的线程,线程的创建,销毁会增加很多资源.
因此就出现了I/O复用这个问题.
运作方式:
1.I/O复用:当这些文件描述符中有任何一个就绪可进行I/O,请通知我.
2.休眠:直到有一个或多个文件描述符准备妥当.
3.唤醒:什么准备就绪了?
4.处理所有就绪可进行I/O的文件描述符而不收到阻挡.
5.回到步骤1,从头开始.
linux提供了三种方案:select,poll,epoll(高级)
select模型:
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h> int select (int n,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout); FD_CLR(int fd, fd_set *set); 将某个文件描述符移除 FD_ISSET(int fd, fd_set *set); 判断fd是否属于分组(可在调用后判断某个文件描述符是否就绪:
if (FD_ISSET(fd, &readfds))
/* fd 可供读取不会受到阻挡 */ FD_SET(int fd, fd_set *set); 将fd加入分组中 FD_ZERO(fd_set *set); 讲分组中所有文件描述符移除
select()系统调用监视的文件描述符分成三个部分,每个部分等待不同的事件:
readfds分组中的文件描述符用于查看是否读取受阻.
writefds分组中的文件描述符用于查看是否写入受阻.
exceptfds分组中的文件描述符用于查看是否有异常或者是否有紧急数据.
调用返回所有可用文件描述符.
参数n等于任何分组中最高编号的文件描述符值+1.
timeout参数是一个指向timeval结构的指针,该结构的定义如下:
#include <sys/time.h> strcut timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
如果此参数不是NULL,那么select() 调用将在tv_sec秒和tv_usec微秒之后返回.(有点强制的意思,就算没有就绪的,也得返回)
select 当返回为正数时,表示已经准备好的描述符数。返回0时表示超时。发生错误返回-1,并且将errno指定为下面的其中一个值:
EBADF 分组中提供了一个无效的文件描述符.
EINTR 等待时捕捉到一个信号,你可以再次调用select().
EINVAL 参数n是负值或者给定timeout是无效值.
ENOMEM 内存不足以完成这项要求.
使用select()去油可以执行的休眠机制
需要可移植性的休眠机制时,往往采用select(), 方法是提供非NULL值的timeout参数,但是三个分组参数全部为NULL:
struct timeval tv;
tv.tv_sec = ;
tv.tv_usec = ;
/* 休眠500毫秒 */
select (, NULL, NULL, NULL, &tv);
当然,Linux也会为高分辨率休眠机制提供接口.
小例子:
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h> #define TIMEOUT 5 /*select的等待时间,以秒为单位 */
#define BUF_LEN 1024 /* 读取缓冲区,以字节为单位 */ int main(void) {
struct timeval tv;
fd_set readfds;
int ret; /* 等候stdin的输入数据 */
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds); /* 等候5秒的时间 */
tv.tv_sec = TIMEOUT;
tv.tv_usec = ; /* 好了,开始提供服务! */
ret = select (STDIN_FILENO + ,
&readfds,
NULL,
NULL,
&tv);
if (ret == -) {
perror ("select");
return ;
} else if (!ret) {
printf("%d seconds elapsed.\n", TIMEOUT);
return ;
} /*
* 我们的文件描述符可供读取了吗?
* (肯定可以,因此他是我们所提供的唯一fd,
* 而且次调用会返回非零值,但是我们还想有自己一默)
*/
if (FD_ISSET(STDIN_FILENO, &readfds)) {
char buf[BUF_LEN+];
int len;
/* 保证不会遭到阻挡 */
len = read (STDIN_FILENO, buf, BUF_LEN);
if (len == -) {
perror ("read");
return -;
}
if (len) {
buf[len] = '\0';
printf ("read: %s\n", buf);
return ;
}
}
fprintf (stderr, "This should not happen!\n");
return ;
}
最新文章
- 【趣事】用 JavaScript 对抗 DDOS 攻击 (下)
- Maven 配置 Selenium + testNG + reportNG 运行环境
- 学习Linux入门50个基本命令
- x01.BitmapHelper:图像处理
- SPOJ GSS3 Can you answer these queries III
- iOS开发中的4种数据持久化方式【二、数据库 SQLite3、Core Data 的运用】
- 自己生成非官方iPhone toolchain的头文件
- Android之日期及时间选择对话框
- ComponentName意思
- tps,qps
- windows phone 8.1开发:触控和指针事件1
- MySQL 内建函数
- Linux下的定时任务 - Cron服务
- python 下载新的模块
- thymeleaf 货币格式化 数字格式化问题
- webpack打包生成多个vendor的配置方法
- 定义一个Rectangle类,该类提供getLength和getWidth方法。
- CentOS6.5 下Haproxy服务的安装与配置
- 可用Active Desktop Calendar V7.86 注册码序列号
- 性能调优之MySQL篇二:MySQL配置文件My.ini配置文件优化
热门文章
- 5、Java并发编程:Lock
- 树莓派 Raspberry Pi 与 micro:bit起手式
- Java开发工程师(Web方向) - 04.Spring框架 - 第2章.IoC容器
- javac 编译过程
- Ubuntu—查看进程并关闭进程
- [mongodb]child process failed, exited with error number 100
- 蓝牙ble数据转语音实现Android AudioRecord方法推荐
- Thunder团队第三周 - Scrum会议5
- P4编程环境搭建遇到的问题与解决方法
- servlet映射路径