Linux

您所在的位置:网站首页 linux特有的io多路复用 Linux

Linux

2024-07-13 23:05| 来源: 网络整理| 查看: 265

一、为什么需要?

看上一篇文章

二、基本思想

 

        #先构造一张有关描述符的表,然后调用一个函数,这些文件描述符的一个或者多个已准备好进行IO操作时的函数才返回;

 

        函数返回时告诉进程那个描述符已就绪,可以进行IO操作。

三、select函数        

 

大部分Unix/Linux都支持select函数,该函数用于探测多个文件句柄的状态变化。

 

1.头文件

 

#include #include #include

 

2.函数体

 

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

 

3.参数

 

nfds:最大的文件描述符+1

 

readfds:读事件的表

 

writefds:写事件的表

 

exceptfds:异常事件的表

 

timeout:超时检测  //填NULL表示一直阻塞,直到文件描述符准备好为止

 

4.宏选项

 用于设置文件描述符

void FD_CLR(int fd, fd_set *set);//把表中的一个文件描述符删除 int FD_ISSET(int fd, fd_set *set);//检测文件描述符是否准备好了,准备好了返回1,否则返回0 void FD_SET(int fd, fd_set *set);//加入到表中 void FD_ZERO(fd_set *set);//清空表

 

5.返回值

         成功:准备好的文件描述符个数

        失败:-1;

        

6.优缺点分析

 

select基本原理:

 

首先创建一张文件描述符表(fd_set),通过使用特有的函数(select),让内核帮助上层用户循环检测是否有可操作的文件描述符,如果有则告诉应用程序去操作。

 

在多路复用IO模型中,会有一个线程不断去轮询多个socket的状态,只有当socket真

 

正有读写事件时,才真正调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用

 

一个线程就可以管理多个 socket,系统不需要建立新的进程或者线程,也不必维护这些线

 

程和进程,并且只有在真正有socket读写事件进行时,才会使用IO资源,所以它大大减少

 

了资源占用。

 

从流程上来看,使用select函数进行IO请求和同步阻塞模型没有太大的区别,甚至还

 

多了添加监视socket,以及调用select函数的额外操作,效率更差。但是,使用select以后

 

最大的优势是用户可以在一个线程内同时处理多个socket的IO请求。用户可以注册多个

 

socket,然后不断地调用select读取被激活的socket,即可达到在同一个线程内同时处理多

 

个IO请求的目的。而在同步阻塞模型中,必须通过多线程的方式才能达到这个目的。

 

这种模型的特征在于每一个执行周期都会探测一次或一组事件,一个特定的事件会触

 

发某个特定的响应。我们可以将这种模型归类为“事件驱动模型”。相比其他模型,使用select的事

 

件驱动模型只用单线程(进程)执行,占用资源少,不消耗太多CPU,同时能够为多客户端提供服务。

 

如果试图建立一个简单的事件驱动的服务器程序,这个模型有一定的参考价值。

 

但这个模型依旧有着很多问题:

 

当需要探测的句柄值较大时,select()接口本身需要消耗大量时间去轮询各个句柄;该模型将事件

 

探测和事件响应夹杂在一起,一旦事件响应的执行体庞大,那么就会导

 

致后续的事件迟迟得不到处理,并且会影响新的事件轮询,在很大程度上降低了事件探测的及时性。

 

所以select机制只适用于"短作业" 处理机制. (处理时间短) 实例代码:

 

       案例一: 利用复用IO,简单解决对多个管道进行写操作时阻塞的问题          #include #include #include #include #include #include #include #include int main(int argc, const char *argv[]) { int fd1 = open("./f1", O_RDWR); int fd2 = open("./f2", O_RDWR); int fd3 = open("./f3", O_RDWR); //1.创建一张文件描述符表 fd_set readfds, tmpfds; FD_ZERO(&readfds); //2.清空表 FD_SET(fd1, &readfds); FD_SET(fd2, &readfds); FD_SET(fd3, &readfds); int maxfd = fd3; tmpfds = readfds; char buf[64] = {0}; int ret, i; while(1) { readfds = tmpfds; ret = select(maxfd+1, &readfds, NULL, NULL,NULL); if(ret == -1) { perror("select"); return -1; } for(i=fd1; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3