跳至主要內容

Java网络编程I/O模型

xw大约 3 分钟NettyJavaNetty

Java共支持三种网络编程I/O模型:BIO、NIO、AIO

BIO

BIO:同步并阻塞,服务器实现模式为一个连接一个线程,当有一个客户端请求时服务器端需要启动一个线程进行处理,示意图如下:

流程:

  • 服务端启动一个ServerSocket
  • 客户端启动Socket对服务器通讯,默认情况下服务器需要对每个客户建立一个线程与之通讯
  • 客户端发出请求后,先咨询服务端是否有线程响应,如果没有会被等待或者拒绝
  • 如果有响应,客户端线程会等待请求结束后,再继续执行(阻塞)

NIO

NIO: non-blocking IO,同步非阻塞。NIO有三大核心部分:Channel(通道),Buffer(缓冲区),Selector(选择器)。Java NIO的非阻塞模式,使一个线程从某通道发送请求或者读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。示意图如下:

说明:

  • 每个channel都会对应一个Buffer
  • Selector 对应一个线程,一个线程对应多个channel(连接)
  • 该图反应了有三个channel 注册到 该 selector
  • 程序切换到哪个channel 是由事件决定的
  • Selector会根据不同的事件,在各个通道上切换
  • Buffer 就是一个内存块,底层是有一个数组
  • 数据的读取写入是通过Buffer, 这个和BIO ,BIO 中要么是输入流,或者是输出流,不能双向,但是NIO的Buffer是可以读也可以写,需要flip方法切换channel 是双向的,可以返回底层操作系统的情况,比如Linux 底层的操作系统通道就是双向的

相关概念:

  • 缓冲区(Buffer):一个可以读写的内存块。
  • 通道 (Channel): 类似于流,但可以同时进行读写。
  • Selector 能够检测多个注册的通道上是否有事件发生(注意:多个Channel以事件的方式可以注册到同一个
    Selector),如果有事件发生,便获取事件然后针对每个事件进行相应的处理。这样就可以只用一个单线程去管
    理多个通道,也就是管理多个连接和请求。

NIO非阻塞网络编程关系梳理图

对上图的说明:

  1. 当客户端连接时,会通过ServerSocketChannel 得到SocketChannel
  2. Selector 进行监听select 方法,返回有事件发生的通道的个数.
  3. 将 socketChannel 注册到 Selector 上, register(Selector sel, int ops),一个selector上可以注册多个SocketChannel
  1. 注册后返回一个 SelectionKey, 会和该Selector 关联(集合)
  2. 进一步得到各个 SelectionKey (有事件发生的)
  3. 在通过 SelectionKey 反向获取 SocketChannel,方法 channel()
  4. 可以通过得到的 channel,完成业务处理