Java网络编程I/O模型
大约 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非阻塞网络编程关系梳理图
对上图的说明:
- 当客户端连接时,会通过ServerSocketChannel 得到SocketChannel
- Selector 进行监听select 方法,返回有事件发生的通道的个数.
- 将 socketChannel 注册到 Selector 上, register(Selector sel, int ops),一个selector上可以注册多个SocketChannel
- 注册后返回一个 SelectionKey, 会和该Selector 关联(集合)
- 进一步得到各个 SelectionKey (有事件发生的)
- 在通过 SelectionKey 反向获取 SocketChannel,方法 channel()
- 可以通过得到的 channel,完成业务处理