I/O
即输入/输出,通常指数据在内部存储器和外部存储器或其他周边设备之间的输入和输出。
输入/出(英文:Input/Output,简写为 I/O)是信息处理系统(例如计算器)与外部世界(可能是人类或另一信息处理系统)之间的通信。输入是系统接收的信号或数据,输出则是从其发送的信号或数据。该术语也可以用作行动的一部分;到"运行I/O"是运行输入或输出的操作。
输入/出设备是硬件中由人(或其他系统)使用与计算器进行通信的部件。例如,键盘或鼠标是计算器的输入设备,而监视器和打印机是输出设备。计算器之间的通信设备(如电信调制解调器和网卡)通常运行输入和输出操作。
I/O复用函数
在前面的学习中,我们建立一个连接TCP服务器端和多个客服端建立连接时我们需要使用多线程的方式为每一个客户端分配一个描述符,然后就可以解决多个客户端链接同一个服务器端的并发问题,但是在实际的场景中,往往有很多个客户端来链接服务器端,每次创建一个线程都是会占取到系统的内存,那么可以设想如果客户端的数量足够大,在不断的创建线程的过程中就会导致系统崩溃,那么这里就引入到我们的I/O复用
1.i/o复用
当你编写的程序需要同时处理多个描数字(socket或file或device),你又不知道什么时候应该(比方说有数据可以读了)去操作(读/写)哪个描数字。这时候I/O复用就需要登场了。
那么在tcp建立发客户端和服务器端上,如何判断是否有读操作和写操作呢,我们在之前学习时就提到了有接收缓冲区和输入缓冲区,当接收缓冲区里面有数据时,就意味着系统可以进行读操作了相对应的输入缓冲区里还有空间就可以执行读操作
I/O复用是一种让进程预先“警告”内核能力,使得内核一旦发现进程预先告知时指定的一个或多个I/O条件(就是描述符)就绪(可以读/写了),内核就通知进程。linux有多个调用可实现I/O复用:select、poll继承自Unix系统。pselect是select到Posix版。epoll是linux2.6内核特有的。
这里我们介绍select poll 和epoll
2.select
select相比较我们之前学习的函数就有很智能的一个特点,它工作的原理是判断一个描述符上是否有事件产生,如果有的话就把这个描述符加入它的集合中,然后经过后续处理后再判断,如果没用数据了我们就把这个描述符从它的集合中移除
因此我们使用select函数处理并发问题的步骤就有三个
定义集合
添加和移除描述符
后续处理
我们这里可以看看I/O函数的函数原型
nfds表示要处理的描述符个数,一般都是设置为最大值加1,这样起始就可以从0开始
后面的readfds,writefds和exceptfds都是对应事件(读取,写入,异常)的描述符集合
struct timeval是一个存储超时时间的结构体,可以通过改变它的定义改变超时时间
接下来我们直接使用select函数进行一个tcp服务器端的编写
我们用几个客户端链接它并进行通信 客服端只需要保证ip和端口号与服务器端一致即可
我们可以看到成功建立了链接并完成了通信
3.poll
poll和select函数的内部实现再内核上的效率是差别不大的,但是poll被称为加强版的select函数,因为poll可以存储更多的描述符,以及可以有更多的动作
我用用poll编写一个tcp的服务器端
然后我们编译,再用客户端链接他
4.epoll
epoll的效率要比前两个介绍的函数,因为前两个函数在内核上是使用轮询的方式,但是epoll函数使用的方法是注册回调函数,效率就会大大提到
举一个简单的例子
我作为一个任课教师 我有select poll epoll三位课代表
我让他们三个人就收作业这个问题出个决策
select和poll选择去每个人的座位上收
但是epoll选择让所有人往它哪里交作业
当然epoll对于其它两个函数的区别是它有一个内核事件表
客户端链接发送数据
我们可以看到成功的建立了链接并通信
经过这次介绍 我们就可以不使用多线程的处理方式来解决tcp服务器端的并发问题
其实还有更加简便的方法 下一节我们会继续介绍
ET模式和LT模式
epoll对文件描述符的操作有两种模式:LT (Level Trigger,电平触发)模式和ET(EdgeTrigger,边沿触发〉模式。LT模式是默认的工作模式,这种模式下epoll相当于一个效率较高的poll。当往epoll内核事件表中注册一个文件描述符上的EPOLLET事件时,epoll将以ET模式来操作该文件描述符。ET模式是epoll的高效工作模式。
对于采用LT工作模式的文件描述符,当epoll_wait检测到其上有事件发生并将此事件通知应用程序后,应用程序可以不立即处理该事件。这样,当应用程序下一次调用epoll_wait时,epoll_wait还会再次向应用程序通告此事件,直到该事件被处理。而对于采用ET工作模式的文件描述符,当epoll_wait检测到其上有事件发生并将此事件通知应用程序后,应用程序必须立即处理该事件,因为后续的epoll_wait调用将不再向应用程序通知这一事件。可见,ET模式在很大程度上降低了同一个epoll事件被重复触发的次数,因此效率要比LT模式高。
简单来说,我们可以用一个简单的例子可以来介绍这个模式,我们把LT模式比作你的妈妈,ET模式比作你的女友,LT模式就像你的妈妈叫你吃饭一样,她会重复喊你多次,如果你回答马上然后没有过去,那么她就会来再喊你一次一样。但是ET模式就像你的女友喊你吃饭一样,她只会喊你一次,如果你没去她也不会再叫第二次了。这个比喻比较抽象,但是可以很好的说出LT模式和ET模式的特征
LT模式:如果描述符上有事件,就会一直提醒处理
ET模式:只通知一次,不管是否完全处理了所有事件
那么为什么说epoll函数是i/o函数中最好用的函数呢
因为epoll函数不仅处理方式与其它函数不同,而且epoll函数的工作模式可以是ET模式
因为epoll内部实现是注册回调函数的方式,那么它在相同的环境中执行时,效率就会比轮询的方式高很多
最后我们可以比较select poll epoll函数的区别