1、用户空间和内核空间

操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也可以访问底层硬件设备。为了保护用户进程不能直接操作内核,保证内核的安全,操作系统将虚拟空间划分为两部分,一部分是内核空间,一部分是用户空间。

2、进程切换

内核挂起当前正在cpu上运行的进程,并恢复以前挂起的某个进程的执行。

  • 保存处理机上下文,包括程序计数器和其它寄存器。
  • 更新PCB信息
  • 把进程的PCB移入到相应的队列,如就绪或阻塞队列
  • 选择另一个进程执行,并更新PCB
  • 更新内存管理的数据结构
  • 恢复上下文

3、进程阻塞

正在执行的进程,由于期待某些事件的发生,比如IO,自动执行阻塞原语,进入阻塞状态。这是一种主动行为,只有运行中的进程才可以切换到阻塞状态。在阻塞状态的进程是不占用CPU资源的。

4、I/O模式

标准I/O,数据会先被拷贝到操作系统的内核缓冲区,然后才会从操作系统的内核缓冲区拷贝到应用程序的地址空间。

linux有五种网络模式:

  • 阻塞I/O
  • 非阻塞I/O
  • I/O多路复用
  • 信号驱动I/O(signal driven i/o,不常用)
  • 异步I/O

1、阻塞I/O

用户进程调用recvfrom系统调用,进程进入阻塞状态,等待数据准备好,数据会从内核拷贝到用户内存,然后内核返回结果,用户进程解除block状态,重新运行。

2、非阻塞I/O

用户进程调用read操作,如果数据还没准备好,内核立刻返回error,用户进程不会阻塞。用户进程可以通过反复调用read操作轮询来获得数据。

3、I/O多路复用

I/O multiplexing,也就是select、poll、epoll,也可以被称为event driven I/O。好处是单个进程可以处理多个网络I/O,原理就是select、poll、epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达时,就通知用户进程。

用户进程调用了select,整个进程会被block,同时,kernel会监听所有负责的socket,当有一个socket的数据准备好了,select会返回,用户进程再调用read操作,将数据从内核拷贝到用户进程。如果处理的并发连接数不是很高,使用select、poll、epoll的服务端性能不一定比使用multi-threading + blocking IO的服务端性能好。I/O多路复用时,每一个socket,一般设置为非阻塞模式。

5、I/O多路复用

  • select

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)

select函数监视的文件描述符分3类,分别是readfds、writefds、exceptfds。调用select函数会阻塞,直到有描述符就绪或者超时,函数返回。当select函数返回后,可以通过遍历fdset,找到就绪的描述符。

select可以良好的跨平台。缺点是单个进程能够监视的文件描述符的数量存在最大限制。在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制。

  • poll

int poll(struct pollfd *fds, unsigned int nfds, int timeout)
struct pollfd {
int fd;
short events; // requested events to watch
short revents; //returned events witnessed
}

pollfd结构包含了要监视的event和发生的event,不再使用select『参数-值』传递的方式。pollfd没有最大数量限制,但仍需要轮询返回的pollfd来获取就绪的文件描述符。随着监视的文件描述符数量的增长,效率也会线性下降。

  • epoll

    和select、poll相比,epoll更加灵活,没有描述符的限制。epoll使用一个文件描述符管理多个描述符,将用户进程的文件描述符事件存放在内核的一个事件表中,这样在用户空间和内核空间只需copy一次。

int epoll_create(int size)

创建一个epoll的句柄,size用来告诉内核监听的数目。size并不是限制了epoll所能监听的最大描述符个数,只是对内核初始分配内部数据结构的一个建议。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

函数对指定描述符fd执行op操作。op取值由三个宏表示:添加EPOLL_CTL_ADD,删除EPOLL_CTL_DEL,修改EPOLL_CTL_MOD。epoll_event告诉内核需要监听什么事。

typedef union epoll_data {
void *ptr;
int fd;
_uint32_t u32;
_uint64_t u64;
} epoll_data_t;
struct epoll_event {
_uint32_t events;
epoll_data_t data;
}; //epoll events
EPOLLIN:表示对应的文件描述符可读(包括对端SOCKET正常关闭)
EPOLLOUT: 表示对应的文件描述符可写
EPOLLPRI: 表示对应的文件描述符有紧急数据可读(带外数据)
EPOLLERR: 表示对应的文件描述法发生错误
EPOLLHUP: 表示对应的文件描述法被挂起
EPOLLET: 设置为边缘触发
EPOLLONESHOT: 只监听一次事件,当监听完这次事件后,如果还需要监听这个socket,需要再次把这个socket加入epoll
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)

参数events表示内核得到的事件的集合。maxevents告知内核这个events有多大,取值不能大于创建epoll_create()时的size。参数timeout时超时时间(ms,0表示立刻返回,-1表示不确定,也有说法是永久堵塞)。该函数返回需要处理的事件数目,如返回0表示已超时。

6、epoll工作模式

两种:LT(level trigger), ET(edge trigger)。缺省是LT。

  • LT: 当epoll_wait检测到描述符事件发生时,将此事件通知应用程序。应用程序可以不立即处理该事件,下次调用epoll_wait时,会再次响应应用程序并通知。
  • ET: 当epoll_wait检测到描述符事件发生时,将此事件通知应用程序。应用程序必须立即处理该事件,下次调用epoll_wait时,不会再次通知此事件。

LT是缺省工作模式,支持block和non-block socket。ET是高速工作模式,只支持non-block。

7、总结

在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描。epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。epoll监视的描述符的数量不受限制,它所支持的FD上限是系统最大可打开文件数目。

i/o多路复用笔记的更多相关文章

  1. 7.24 IO多路复用和协程代码笔记

    1. 复习 # !/usr/bin/env python # !--*--coding:utf-8 --*-- # !@Time :2018/7/23 11:49 # !@Author TrueNew ...

  2. Java IO学习笔记六:NIO到多路复用

    作者:Grey 原文地址:Java IO学习笔记六:NIO到多路复用 虽然NIO性能上比BIO要好,参考:Java IO学习笔记五:BIO到NIO 但是NIO也有问题,NIO服务端的示例代码中往往会包 ...

  3. Java IO学习笔记七:多路复用从单线程到多线程

    作者:Grey 原文地址:Java IO学习笔记七:多路复用从单线程到多线程 在前面提到的多路复用的服务端代码中, 我们在处理读数据的同时,也处理了写事件: public void readHandl ...

  4. python学习笔记-(十四)I/O多路复用 阻塞、非阻塞、同步、异步

    1. 概念说明 1.1 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可 ...

  5. HTTP/2笔记之流和多路复用

    零.前言 本部分将讲解HTTP/2协议中对流的定义和使用,其实就是在说HTTP/2是若何做到多路复用的. 一.流和多路复用的关系 1. 流的概念 流(Stream),服务器和客户端在HTTP/2连接内 ...

  6. python 学习笔记12(事件驱动、IO多路复用、异步IO)

    阻塞IO和非阻塞IO.同步IO和异步IO的区别 讨论背景:Linux环境下的network IO. 1.先决条件(几个重要概念) 1.1.用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32 ...

  7. python学习笔记10--协程、IO、IO多路复用

    本节内容 一.协程 1.1.协程概念 1.2.greenlet 1.3.Gevent 1.4.协程之爬虫 1.5.协程之socket 二.论事件驱动与异步IO 三.IO 3.1.概念说明 3.2.IO ...

  8. io多路复用,select,笔记

    一下代码,是摘自大王的博客,(http://www.cnblogs.com/alex3714/)我自己有加了些注释. 1 2 3 #_*_coding:utf-8_*_ 4 5 __author__ ...

  9. STM32学习笔记——OLED屏

    STM32学习笔记--OLED屏 OLED屏的特点: 1.  模块有单色和双色可选,单色为纯蓝色,双色为黄蓝双色(本人选用双色): 2.  显示尺寸为0.96寸 3.  分辨率为128*64 4.   ...

随机推荐

  1. 怎样在一个fragment or 随意类中操作还有一个fragment中的方法

    1 怎样在acitivty中运行fragment中的方法: 首先获得这个Fragment的对象 xxxFragment fragmentObject = (xxxFragment) getFragme ...

  2. 线程堆栈大小 pthread_attr_setstacksize 的使用

    pthread_create 创建线程时,若不指定分配堆栈大小,系统会分配默认值,查看默认值方法如下: # ulimit -s8192# 上述表示为8M:单位为KB. 也可以通过# ulimit -a ...

  3. Android java.lang.IllegalStateException: Already logged in to server.

    今晚在搞openfire时,无意中发现了这样的一个问题:问题描述: java.lang.IllegalStateException: Already logged in to server.原因:wh ...

  4. 使用Kotlin开发Android

    查看我的所有开源项目[开源实验室] 欢迎增加我的QQ群:[201055521],本博客client源代码下载[请点击] 摘要 我首先声明我并没有使用Kotlin非常长时间,我差点儿是在学习的同一时候写 ...

  5. poj 2689 Prime Distance(大区间筛素数)

    http://poj.org/problem?id=2689 题意:给出一个大区间[L,U],分别求出该区间内连续的相差最小和相差最大的素数对. 由于L<U<=2147483647,直接筛 ...

  6. IT增值服务客户案例(二):河南郑州大四实习生,职业规划和项目开发指导

    客户整体情况,河南郑州大四在校学生,目前在企业实习,从事Java开发工作.有一定的项目开发经验,对Java周边技术有基本的理解. 客户购买的是"拜师学艺"服务,按月付款. 经过多次 ...

  7. Go语言学习(十)bytes包处理字节切片

    bytes包提供了对字节切片进行读写操作的一系列函数 字节切片处理的函数比較多,分为基本处理函数,比較函数,后缀检查函数,索引函数,切割函数, 大写和小写处理函数和子切片处理函数等. 1.字节切片基本 ...

  8. [Javascript] Write a function pipeline

    const _pipe = (f, g) => (...args) => g(f(...args)) export const pipe = (...fns) => fns.redu ...

  9. Android与IOS的UUID的区别

    UUID含义是通用唯一识别码 (Universally Unique Identifier),这 是一个软件建构的标准,也是被开源软件基金会 (Open Software Foundation, OS ...

  10. Eclipse 一直不停 building workspace... 完美解决总结

    Eclipse 一直不停 building workspace... 一.产生这个问题的原因多种 1.自动升级 2.未正确关闭  3.maven下载lib挂起 等..二.解决总结 (1).解决方法  ...