多路转接介绍及代码实现
目录
1.多路转接技术的产生背景
2.select
3.poll
3.epoll
1.多路转接技术的产生背景
一个技术的出现必然有它要解决的问题,那么多路转接解决的问题是什么嗯?
我们知道,一个进程里面有一个文件描述符表管理这个进程所打开的文件,我们进行网络通信的时候,本质就是创建一个网络文件进行通信,我们可能会同时多个文件进行通信。
文件进行通信,不就是进行IO吗?就要进行读取,就要进行写入,但是在网络中,我们数据的发送需要时间,我们一个一个等就是串行的,效率低下,为了解决这种问题,我们提出多路转接,就是OS提供系统调用,底层去同时等待多个fd,而非去等待一个fd,假如我们一秒一个文件准备就绪的概率是百分之一,如果我同时等待100个文件,理论上几乎每秒都会有文件就绪,所以大大降低了我们等待的时间,我们IO抽象出来就是等待+拷贝,读是一种拷贝,写也是一种拷贝,通常,我们等待的时间是大于拷贝的时间,我们通过多路转接的形式,不就可以降低等待的时间,单位时间内更多的数据被拷贝,效率提高。
我们在代码中的scanf不就是一种等待吗?如果我的数据不输入,它就一直在那里阻塞,当键盘数据准备就绪,触发硬件中断,通知操作系统去处理键盘的数据,这样效率低下,我们等的时间太长了,所以我们要对我们读取的文件进行非阻塞的设计。
键盘不就绪抽象出来就是读的条件不就绪,我把文件设计成非阻塞模式,那么它就不会阻塞住。
fcntl的第一行是获取选项,然后第二个是对fd的模式进行设计,采用|可以对模式进行添加。
如果我们的文件read条件不就绪就会出错,这里就会引发两种情况,一种是我的read真的出错了,一种是我的read数据没有准备好,没有真的出错,我们需要对这种情况进行处理。
在我们的read错误会返回对应的错误码,我们可以用errno对错误码进行提取,判断,如果是读的条件未就绪,我们就放行,让它进行下一次检查,如果写端关闭read返回0,如果错误,返回小于0 的数,直接break;
errno是一个全局变量。
EINTR表示当我们正在读取的时候,它进行了线程切换,导致我们读到一半失败了,再回来的时候可能就不再读取了,我们还需要再次进行读取。
#include<iostream>
#include<unistd.h>
#include<fcntl.h>
void setnoblock(int fd)
{int fl=fcntl(fd,F_GETFL);fcntl(fd,F_SETFL,fl | O_NONBLOCK);
}
int main()
{ setnoblock(0);//设置为非阻塞char buffer[64];while(true){int n=read(0,buffer,sizeof(buffer)-1);if(n>0){// buffer[n]=0;printf("#%s",buffer);}else if(n==0){perror("read");break;}else {if(errno==EAGAIN){printf("你的数据没有准备好,下次再来\n");//在这里下面的逻辑就可以做其他事情了。sleep(1);continue;}else if(errno==EINTR){continue;}else{perror("read");break;}}}return 0;
}
2.select
知道了多路转接的来源之后,我们了解多路转接就是为了提高IO效率而诞生的,所以我们来介绍一下具体的系统为我们提供的接口select。IO=等+拷贝,select为了降低等的时间而诞生。
是一种具体的方案,而不是一种抽象的所谓的降低等的效率的抽象概念。这里认为任何抽象的概念都应该建立在具体的实现上面,没有实践理解, 怎么理解这么抽象的概念?
、、 它的功能是监视有没有文件描述符发生变化。
sel