NIO
简介
- 随着JavaIO类库的不断发展和改进,基于Java的网络编程会变得越来越简单。随着异步IO功能的增强,基于JavaNIO开发的网络服务器甚至不逊色与C++开发的网络程序。
- 记录一下学习BIO、NIO以及JDK1.7提供的NIO2.0的使用。
传统的BIO编程
- 这个可以搜索一下socket,就有很多。
- 通过一个线程来监听所有的socket连接,连接成功则新建线程去处理客户端操作。
- 问题是伸缩性差,随着并发访问量增大,会很好系统资源,可能造成处理失败。由于是阻塞时的读写,会造成较大的读写延迟。
- 源码略。
伪异步IO编程
- 为了解决传统的编程模型问题,有人使用线程池或者消息队列实现N各线程处理M个客户端的模型。M远大于N。
模型图
- Acceptor是一个线程,通过死循环来监听socket连接,如果有连接成功,则新建Runnable对象,提交给线程池处理。
源码分析
- 跟BIO的代码差不多,只是在Server端加了线程池,来处理客户端socket连接。并将连接封装到Runnable对象,并交给ThreadPool处理。
弊端
- 通过以上模型及代码分析,很容易知道通信底层还是使用的socket,读写还是同步阻塞的,因此,以上优化只是减小了过多创建销毁线程的开销,并不能从根本上解决阻塞读写产生的问题。
NIO编程
简介
- NIO(New I/O),较多人喜欢称作Non-block I/O.
- NIO新增了SocketChannel和ServerSocketChannel两种套接字通道。都支持阻塞和非阻塞两种模式。
- 相关概念
- 缓冲区Buffer
- 缓冲区实际上是一个数组,封装了对数据结构化访问以及维护读写位置等信息。
- 在NIO库中,所有数据都是用缓冲区处理的,在读取数据时,直接读取到缓冲区。写入数据时,直接写入写缓冲区。任何时候访问NIO中的数据,都是 通过缓冲区进行操作。
- 最常用的的缓冲区是ByteBuffer。大部分Java基本类型都对应一种缓冲区。类图如下
- 通道channel
- Channel 是一个通道,可以通过它读取和写入数据。InputStream和OutputStream各自只能在一个方向上操作。
- Channel是全双工的,所以它可以比流更好地映射底层的api。
- Channel类图如下:
- 多路复用器Selector
- Selector是NIO的编程基础。多路复用器提供选择已经就绪的任务的能力。
- Selector会不断轮询注册在其上的Channel,如果channel上面有了新的TCP连接、读取或者写事件,这个channel就是就绪状态,会被Selector轮询出来。然后通过SelectionKey集合可以获取就绪的Channel集合,进行IO操作。
*一个Selector可以同时轮询多个Channel,由于JDK使用了epoll()代替传统的select实现,所以没有最大连接句柄1024/2048的限制。这意味着只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端。
- 缓冲区Buffer
NIO服务端序列图
* 未完待续