一、文件描述符
文件描述符是已被打开文件的索引,目的是为了方便管理已被打开的文件。
具体的,我也不了解。。。。
二、I/O多路复用
I/O多路复用技术也就是事件驱动模型。
总结参考1对I/O多路复用的描述:
-
最开始互联网用户较少时,为了支持一个服务器连接多个客户端,每当有一个请求到来时,服务器就新开一个进程/线程1去处理这个请求。
-
但是随着用户越来越多,这种方法显然不再适用,于是发明了I/O多路复用技术,但是此时的多路复用技术是当有一个请求到来时,它会去遍历所有已经注册的文件描述符,找到要处理的那个文件描述符,但是这个方法产生的问题是,如果注册的文件描述符数量多大,那么就会造成cpu爆炸。
三、用户态和内核态
内核态:cpu可以访问内存中的任何数据,包括外围的设备,比如:硬盘、网卡,cpu也可以将自己从一个程序切换到另外一个程序中。
用户态:只能访问部分cpu数据,并且不能访问外围设备,占用cpu的能力被掠夺,cpu资源可以被其他的程序获取。
四、select、poll、epoll
select、poll、epoll都是基于I/O多路复用的。
1、select函数
I/O多路复用技术被提出之后,select函数是第一个实现的,它的缺点如下:
-
每次调用select函数时,都需要把文件描述符集合从用户态拷贝到内核态,如果文件描述符集合很大,那么这个耗时很长。
-
同时每次调用select函数时,select函数都会遍历内核态中的文件描述符集合,找出要处理的文件描述符,这在遍历数据量很大的文件描述符集合时非常耗时(cpu爆炸)。
-
select的文件描述符数量只有1024个,非常小(我的理解是只能同时连接1024个请求)。
2、poll
poll和select的原理一样,只不过支持大于1024个文件描述符。
3、epoll
假设:同时有100万个用户和一个nginx进程保持TCP连接,而同一时刻只有几十或者几百个连接是活跃的(有网络事件),所以进程只需要处理这些活跃的数据就可以了。
-
调用epoll_create方法创建一个epoll对象,在这个epoll对象中创建一个红黑树和一个链表。
-
调用epoll_ctl方法向epoll对象中的红黑树添加文件描述符(创建连接时),内核中断处理程序会注册一个回调函数,当有网络事件时,该回调函数触发,该事件对应的文件描述符被添加到链表中。
-
epoll_wait会去看链表是否为空,如果没空进入sleep状态,如果不为空,就去处对应的文件描述符进行处理。
select和poll是对所有的连接的文件描述符进行遍历,查找要处理的那个文件描述符,而epoll是对活跃连接的文件描述符进行遍历,活跃连接相对于所有的连接来说,数量非常非常少,所以这就大大的减少了遍历时间和cpu的压力。
五、epoll、poll、select的对比
如图所示,当文件描述符数量增加时,select、poll处理请求所需要的时间就会急剧增加,而epoll所需的时间和文件描述符无关。
参考: