I/O多路转接服务器设计(select,poll,epoll)

I/O多路转接服务器设计(select,poll,epoll)

select和poll服务器代码:https://github.com/zzaiyuyu/select-poll

理解IO

IO就是数据的输入输出过程,一般程序运行中的数据都在内存中存放,当cpu想进行数据交换就需要IO操作,linux系统实现的是缓存IO

缓存IO就是底层数据到来时,先被拷贝到内核缓冲区,然后再从内核缓冲区拷贝到程序的地址空间。

所以当调用read等系统调用,是会切换到内核态然后进行等待数据就绪,然后再将数据拷贝到进程的地址空间。

在上述等待期间,只要数据没有就绪,read调用不会返回,这中方式称为阻塞IO。文件描述符的读取默认都是阻塞形式。

下面是另外4种IO模型

非阻塞IO区别就在于等待数据时,如果没有就绪,那么read调用立刻返回错误码。这样为了保证能读到数据就得轮询,反复读取文件描述符。

IO多路转接利用select同时等待多个文件描述符,只要有一个文件描述符数据就绪,select就返回。

异步IO类似于回调机制,进程不需要等待数据就绪,内核完成数据拷贝后通知应用程序用数据就可以了。信号驱动IO是内核告诉进程何时数据已经就绪。

结论:所有IO都需要有两个步骤,内核等待数据就绪,拷贝数据到进程地址空间。高效IO就是想办法减少等待数据的时间。

阻塞和非阻塞

设置文件描述符为阻塞,那么调用read读取就会切换内核态开始等待数据就绪,只要数据没来就挂起当前进程直到有数据来才唤醒进程并返回read调用。

这样看来阻塞是在说进程等待read调用时自身的运行状态!非阻塞就是不挂起的等待调用。

具体的read,write使用细节。
read阻塞buf为空则挂起等待,否则返回实际读到的字节数。
read非阻塞buf为空返回-1,并设置错误码EAGAIN,否则也返回实际读到字节数。
write阻塞,只有在缓冲区完全放得下数据才返回调用,否则挂起等待缓冲区就绪。
write非阻塞,在缓冲区放不下全部数据返回实际放入的字节数,缓冲区为空返回-1.
https://www.cnblogs.com/junneyang/p/6126635.html

异步和同步

同步与异步主要是从消息通知机制角度来说的。

上述阻塞IO,IO复用,信号驱动IO都属于同步IO。因为对IO的读写操作都是在等待IO,内核缓冲区就绪后通知用户。异步IO而言,用户可以直接对IO进行读写操作,然后立即返回,将数据从内核拷贝到程序地址空间这个操作由内核接管,然后通知用户IO 已完成

比如阻塞IO,read返回后的值一定能给调用者数据或者错误信息,调用者根据返回值决定下一步改怎么做。这就是同步通信。

而异步IO,调用aio_read立即返回,不关心这个返回值,当操作系统做完数据拷贝后用信号通知进程进行IO完毕之后的操作就可以了。这就是异步通信。

总结:同步是调用者主动等待调用返回值,异步是系统通知调用者调用完成了

二者的关键区别就是效率问题,同步方式总是需要检测调用结果的,很浪费资源。

https://www.jianshu.com/p/aed6067eeac9

以上是IO概念的同步异步,在进程中,同步是指各个进程执行的顺序制约关系。

select服务器的设计思路

普通服务器思路:

  1. 设置监听套接字(创建套接字,绑定地址)
  2. accept读取监听套接字,若有连接来建立连接并处理数据请求

关键在于accept读取监听套接字是阻塞的,如果没有连接来则进程会挂起。

使用select同时读取监听套接字和数据套接字,只要有一个套接字数据就绪就进行处理,这种方式就是IO多路转接,就绪事件通知机制。select在底层对IO读写是非阻塞的,阻塞的是select的系统调用。

编写细节:select的参数是输入输入型,利用位图输入时让用户告诉操作系统关心哪些文件描述符上的读/写事件就绪。输出时操作系统告诉用户哪些文件描述符就绪。

epoll服务器

epoll是性能非常好的多路IO就绪事件通知机制。

使用epoll的关键步骤:

  1. 调用epoll_create创建epoll模型
  2. 调用epoll_ctl告诉内核用户关心哪些文件描述符上的事件
  3. epoll_wait是内核告诉用户哪些文件描述符就绪了,此时再进行数据操作

epoll模型是操作系统维护的一个结构,一个就绪队列,一个红黑树和一个回调机制。

使用epoll_ctl就是操纵红黑树增删改结点,结点是key-value的,用文件描述符作为key值。在有文件描述符事件就绪时,驱动的回调机制将红黑树结点放入就绪队列,同时epoll_wait发现队列不为空,则取出文件描述符进行处理。

epoll的优点——对应select,poll

select的优点

  1. 是相对于多进程多线程说的,处理多个连接请求没有进程切换带来的开销
  2. 可以做到单进程处理多连接请求。

select的缺点

  1. select设计上有同时等待文件描述符上限
  2. 在select调用前循环设置关心的文件描述符,在select返回后要循环检测哪些文件描述符就绪,这些都需要系统调用切换到内核态,随着连接数增加是有很大开销的

poll改进了select的接口,将文件描述符和关心的事件绑定到结构体里,之后定义一个全局结构体数组,对数组增删改就可以。select的输入输出型位图参数需要在调用select前重新设置,poll接口没有这个弊端。但是未解决根本问题,依旧需要循环检测。

epoll的优点

  1. 文件描述符没上限,利用红黑树结点
  2. 利用回调机制将就绪的文件描述符加入就绪队列,即使文件描述符增多,不会影响判断就绪的性能
  3. epoll_wait发现就绪队列不空则返回,此时在队列中取走已经就绪的文件描述符。不在需要循环检测,是一个O(1)操作

网上很多资料说epoll还有一个mmap内存映射,但个人认为不正确。若是直接将就绪队列映射到用户空间,那么epoll_wait将不需要传入一个buf空间去获取就绪队列内容。而且考虑安全问题,内核也不应该把就绪队列映射到用户空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值