【计算机网络】IO模型

概述

  • socket 将网络中的通信抽象成 I/O 操作, 可以对 socket 像文件一样的打开, 读写和关闭。

  • I/O 模型一般指磁盘 I/O 和网络 I/O

  • I/O 模型共有五种,分为两类

    • 同步
      • 阻塞式 I/O (blocking I/O)
      • 非阻塞式 I/O (non - blocking I/O)
      • I/O多路复用(multiplexing I/O)
      • 信号驱动式 I/O (signal - driven I/O)
    • 异步
      • 异步 I/O (asynchronous I/O)
  • 对 I/O 的一次访问一般包括两个阶段

    • 等待数据准备好(等待数据到达或等待数据复制到系统内核缓冲区)
    • 将数据从内核缓冲区复制到应用进程缓冲区

同步阻塞 I/O

在JDK1.4之前,Java中主要是用的就是阻塞IO,叫做BIO


发起 IO 请求后进程被阻塞, 直到数据从内核缓冲区复制到应用进程缓冲区为止。

同步非阻塞 I/O

JDK1.4后提供了 NIO, 即同步非阻塞 I/O


发起 IO 请求后, 系统内部会以非阻塞的形式来执行 I/O , 即如果底层数据没有准备就绪, 那么内核返回异常信息, 之后接着继续不断的执行系统调用来获知 I/O 是否完成, 这种方式也称轮询(polling)

非阻塞只是指内部在不断轮询,不会被阻塞。同步是指在调用了NIO接口后, 还是需要一直同步等待,

I/O 多路复用

调用 select 或者 poll 等待多个socket, 能够实现对多个 IO 端口的监听, 其中任意一个socket准备好了, 就能返回可读, 之后再调用recvform系统调用, 将数据由内核态拷贝到用户进程, 这个过程是阻塞的。

信号驱动 I/O

应用进程使用sigaction系统调用, 内核立即返回, 应用进程可继续执行, 内核等到数据到达时向应用程序发送SIGIO信号, 应用进程收到信号后调用recvfrom将数据从内核复制到应用进程中

异步 I/O

jdk1.7之后支持AIO, 即异步IO模型。


应用进程执行 aio_read 系统调用后会立即返回, 进程可继续运行, 不会被阻塞, 内核在所有操作完成后会向应用进程发送信号。

五大 I/O 模型比较

  • 同步和异步: 主要区别在第二阶段应用进程是否会阻塞, 在调用具体的JDK方法时, 同步不会立即返回, 而异步会直接返回继续执行。
  • 同步的阻塞和同步的非阻塞: 指第一阶段是否会阻塞, 而第二阶段都会阻塞.

select poll 和 epoll

select poll 和 epoll都是 I/O 多路复用的具体实现,先出现的是select 之后是 poll 和 epoll。
I/O 多路复用监视多个描述符,当某个描述符准备就绪, 就通知程序进行相应的读写操作。

select

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  • fd_set 由数组实现, 数组大小有限制, 无法监听大量的描述符.
  • timeout 为超时参数, 调用 select 会一直等待到有描述符事件或者时间超时

select 每次轮询 fd 文件描述符检查就绪时间

缺点

  • 每次调用都需要将fd拷贝到内核, 开销大
  • 每次都需要遍历fd
  • select 支持的文件描述符太小, 默认是1024.

poll

int poll(struct pollfd *fds, unsigned int nfds, int timeout);

poll 和 select 的功能基本相同, 只是描述fd集合的方式不同, poll使用pollfd结构, 从而解决了单独线程能够打开文件描述符的数量有限制的问题.

epoll

int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

epoll 不需要通过轮询来获得世界完成的描述符,已注册的描述符在内核中会被维护在一棵红黑树上,通过回调函数内核会将 I/O 准备好的描述符加入到一个链表中管理, epoll 不断轮询就绪链表, 避免了将描述符从进程缓冲区向内核缓存区的重复拷贝.

  • epoll的默认工作模式为LT边缘触发: 已通知的事件如果未被处理则下次依然被通知
  • ET模式水平触发: 已通知的事件必须被处理并且不再通知此事件

应用场景

  • select

select 的 timeout 精度为1ns, 而 poll 和 epoll 为 1ms, 因此 select 适合实时性高的场景

select 的可移植性更好, 几乎被所有主流平台支持.

  • poll

如果有大量描述符, 且对实时性要求不高的场景, 应该使用 poll 而不是 select

  • epoll

仅适用于 linux

有大量的描述符需要同时轮询, 且连接最好是长连接。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章