多路 io 中得 select poll epoll得区别

种方式是存在问题的。

可以打个比方:如果我们先前创建的几个进程承载不了目前快速发展的业务的话,是不是还得增加进程数?我们都知道系统创建进程是需要消耗大量资源的,所以这样就会导致系统资源不足的情况。

那么有没有一种方式可以让一个进程同时为多个客户端端提供服务?

接下来要讲的IO复用技术就是对于上述问题的最好解答。

对于IO复用,我们可以通过一个例子来很好的理解它。(例子来自于《TCP/IP网络编程》)

某教室有10名学生和1名老师,这些学生上课会不停的提问,所以一个老师处理不了这么多的问题。那么学校为每个学生都配一名老师,

也就是这个教室目前有10名老师。此后,只要有新的转校生,那么就会为这个学生专门分配一个老师,因为转校生也喜欢提问题。如果把以上例子中的学生比作客户端,那么老师就是负责进行数据交换的服务端。则该例子可以比作是多进程的方式。

后来有一天,来了一位具有超能力的老师,这位老师回答问题非常迅速,并且可以应对所有的问题。而这位老师采用的方式是学生提问前必须先举手,确认举手学生后在回答问题。则现在的情况就是IO复用。

目前的常用的IO复用模型有三种:select,poll,epoll。

 

select模型:

说的通俗一点就是各个客户端连接的文件描述符也就是套接字,都被放到了一个集合中,调用select函数之后会一直监视这些文件描述符中有哪些可读,如果有可读的描述符那么我们的工作进程就去读取资源。PHP 中有内置的函数来完成 select 系统调用。

函数原型:

int socket_select (array &$read ,array &$write ,array &$except ,int $tv_sec [,int $tv_usec= 0 ])

作用说明:用于确定一个或多个套接字的状态,对每一个套接字,调用者可查询它的可读性、可写性及错误状态信息

参数说明:

read: 指向一组等待可读性检查的套接字

write: 指向一组等待可写性检查的套接字

except: 指向一组等待错误检查的套接字

tv_sec: 用来设置 select() 的等待时间,秒

tv_usec: 用来设置 select() 的等待时间,微妙

 

这里注意一下,如果 tv_sec 设置为0,则 socket_select 立即返回,也就是非阻塞的。如果 tv_sec 设置为 null ,则 socket_select 将一直阻塞到有套接字满足条件。

poll模型:

poll 和 select 的实现非常类似,本质上的区别就是存放 fd 集合的数据结构不一样。select 在一个进程内可以维持最多 1024 个连接,poll 在此基础上做了加强,可以维持任意数量的连接。

但 select 和 poll 方式有一个很大的问题就是,我们不难看出来 select 是通过轮训的方式来查找是否可读或者可写,打个比方,如果同时有100万个连接都没有断开,而只有一个客户端发送了数据,所以这里它还是需要循环这么多次,造成资源浪费。

 

所以后来出现了 epoll系统调用。

 

epoll模型:

epoll 是 select 和 poll 的增强版,epoll 同 poll 一样,文件描述符数量无限制。

epoll是基于内核的反射机制,在有活跃的 socket 时,系统会调用我们提前设置的回调函数。而 poll 和 select 都是遍历。

但是也并不是所有情况下 epoll 都比 select/poll 好,比如在如下场景:

在大多数客户端都很活跃的情况下,系统会把所有的回调函数都唤醒,所以会导致负载较高。既然要处理这么多的连接,那倒不如 select 遍历简单有效。

posted on 2020-07-01 16:59  王大拿  阅读(91)  评论(0)    收藏  举报

导航