操作系统之网络IO( 二 )


【操作系统之网络IO】④信号驱动IO模型:首先开启套接口信号驱动IO功能,并通过系统调用为SIGIO信号绑定一个信号处理函数,此时请求即刻返回,当内核数据准备就绪时,就给对应进程发送SIGIO信号,进程接收到该信号后,会通过信号处理程序来通知应用程序调用来读取数据 。
⑤异步IO:应用程序告知内核启动某个操作,并让内核在整个操作完成之后通知应用程序,比如说内核已经将数据准备好并已经将其拷贝到用户空间中了 。这种模型与信号驱动模型的主要区别在于,信号驱动IO只是由内核通知我们何时可以开始IO操作,而异步IO模型是由内核通知我们操作何时已经完成 。
IO多路复用 /poll
实现多路复用的方式是,将多个已连接的都放到一个文件描述符集合,然后调用函数将文件描述符集合拷贝到内核里,内核通过顺序遍历文件描述符集合的方式来检查是否有网络事件产生,当检查到有事件产生后,将此标记为可读或可写, 接着再把整个文件描述符集合拷贝回用户态里,然后用户态还需要再通过遍历的方法找到可读或可写的 ,然后再对其处理 。
缺点:
单个进程能够监视的文件描述符的数量存在最大限制,通常是1024,当然可以更改数量,但由于采用轮询的方式扫描文件描述符,文件描述符数量越多,性能越差;需要通过遍历的方式来找到可读或可写的文件描述符,时间复杂度为O(n);每次调用都需要会产生两次文件描述符集合的拷贝;
poll以链表形式来组织文件描述符集合,不再有单个进程文件描述符个数限制,当然还会受到系统文件描述符限制 。除此之外它的实现方式和并没有区别,所以还是会存在上述的缺点2和3 。
epoll
epoll在内核里使用红黑树来管理所有待检测的文件描述符,用户程序只需要通过 () 函数将需要监控的 加入内核中的红黑树里,这样就不需要像 /poll 每次操作时都要拷贝整个文件描述符集合到内核,而只需要传入一个待检测的 ,减少了内核和用户空间大量的数据拷贝 。
epoll 使用事件驱动的机制,内核里维护了一个双向链表来记录就绪事件,当某个有事件发生时,通过回调函数内核会将其加入到这个就绪事件链表中,当用户调用 () 函数时,只会返回有事件发生的文件描述符的个数,不需要像 /poll 那样轮询扫描整个文件描述符集合,因此与执行效率与文件描述符的个数无关,也对文件描述符的个数没有限制 。
触发方式
**水平触发(LT):**当检测到某描述符事件就绪并通知应用程序时,应用程序可以不立即处理该事件;下次调用时,会再次通知此事件
边缘触发(ET): 当检测到某描述符事件就绪并通知应用程序时,应用程序必须立即处理该事件 。如果不处理,下次调用时,不会再次通知此事件 。
/poll只支持水平触发,epoll支持水平触发和边缘触发,但是默认为水平触发 。
模型 单单线程模型
使用一个线程来完成客户端的所有请求,通过IO多路复用接口监听事件,收到事件后通过进行分发,根据事件类型将其分发给 来建立连接或者当前连接对应的来完成业务请求 。
缺点:
所以该模型不适用于计算密集型场景,只适用于业务处理非常快的场景(如Redis) 。
单多线程模型
该模型专门有一个线程(线程)用于处理客户端的TCP连接请求,然后其它的业务请求交由一个线程池来负责 。
在一些场景下,一个线程负责监听和处理所有的客户端连接可能会存在性能问题 。
主从多线程模型
用于接收客户端连接的不再是一个单独的线程,而是一个独立的线程池 。接收到客户端的TCP连接请求并处理完成后,将新建的注册到IO线程池的某个线程上,此后由它来负责该连接后续的读写和编解码工作 。