sum
java 网络编程本质上是 jvm 调用 linux 系统函数完成,所以要掌握操作系统的 io 模型。
linux 系统有 5 种 io 模型
无论哪种 io, 都可以分为两阶段的操作:
- 等待数据从磁盘或者网络到达 kernel;
- 将数据从 kernel 拷贝到用户空间(process)
阻塞 io
阻塞 io 要线程一直等待数据从网络到达并且拷贝到用户空间才返回,这个过程中,这个线程什么都不能做。
非阻塞 io
非阻塞IO模型下,我们发出open/read/write这样的IO操作时,这些操作不会永远阻塞,而是立即返回。非阻塞模型由于立即返回,后面需要轮询不断的查看读写是否已经就绪,然后才能进行I/O操作
io 多路复用
**IO复用模型:Linux提供select/poll,进程通过将一个或多个fd传递给
select 或 poll 系统调用,阻塞在 select;这样 select/poll 可以帮我们侦
测许多 fd 是否就绪。但是 select/poll 是顺序扫描 fd 是否就绪,而且支持
的 fd 数量有限。linux 还提供了一个 epoll 系统调用,epoll 是基于事件驱
动方式,而不是顺序扫描,当有 fd 就绪时,立即回调函数 rollback。
**
异步 io
用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知。IO 两个阶段,进程都是非阻塞的。
io 模型对比
根据严格的定义来说,只有aio 模型才是真正的异步io, 其他的第二阶段都是阻塞的。
Reactor 模型
单线程 reactor 模型
多线程 reactor 模型
Reactor 模型的中心思想是将所有要处理的 IO 事件及其处理器注册到一个中心的IO多路复用器上,并将主线程阻塞在多路复用器上;acceptor 只处理连接事件,当有相应的 IO 事件到达时,多路复用器将IO事件分发给相应的处理器进行处理. netty 实现了 reactor 模型。
java nio
java bio 是基于stream 基于字节的,nio 是基于channel 基于缓冲区 bytebuffer 的。多个channel 可以阻塞到一个 select 上。
**
服务端对应 serverSocketChannel, 客户端对应 SocketChannel 。Selector 是多路复用器,多个 channel 可以阻塞到一个Selector 上。SelectionKey 代表的是 io 事件,比如可读、可写、可建立连接。