声明:本文是《Netty 权威指南》的样章,感谢博文视点授权并发编程网站发布样章,禁止以任何形式转载此文。
下面,我们对NIO服务端的主要创建过程进行讲解和说明,作为NIO的基础入门,我们将忽略掉一些在生产环境中部署所需要的一些特性和功能。
步骤一:打开ServerSocketChannel,用于监听客户端的连接,它是所有客户端连接的父管道,代码示例如下:
1 |
ServerSocketChannel acceptorSvr = ServerSocketChannel.open(); |
步骤二:绑定监听端口,设置连接为非阻塞模式,示例代码如下:
1 |
acceptorSvr.socket().bind( new InetSocketAddress(InetAddress.getByName(“IP”), port)); |
2 |
acceptorSvr.configureBlocking( false ); |
步骤三:创建Reactor线程,创建多路复用器并启动线程,代码如下:
1 |
Selector selector = Selector.open(); |
2 |
New Thread( new ReactorTask()).start(); |
步骤四:将ServerSocketChannel注册到Reactor线程的多路复用器Selector上,监听ACCEPT事件,代码如下:
1 |
SelectionKey key = acceptorSvr.register( selector, SelectionKey.OP_ACCEPT, ioHandler); |
步骤五:多路复用器在线程run方法的无限循环体内轮询准备就绪的Key,代码如下:
1 |
int num = selector.select(); |
2 |
Set selectedKeys = selector.selectedKeys(); |
3 |
Iterator it = selectedKeys.iterator(); |
5 |
SelectionKey key = (SelectionKey)it.next(); |
步骤六:多路复用器监听到有新的客户端接入,处理新的接入请求,完成TCP三次握手,建立物理链路,代码示例如下:
1 |
SocketChannel channel = svrChannel.accept(); |
步骤七:设置客户端链路为非阻塞模式,示例代码如下:
1 |
channel.configureBlocking( false ); |
2 |
channel.socket().setReuseAddress( true ); |
步骤八:将新接入的客户端连接注册到Reactor线程的多路复用器上,监听读操作,用来读取客户端发送的网络消息,代码如下:
1 |
SelectionKey key = socketChannel.register( selector, SelectionKey.OP_READ, ioHandler); |
步骤九:异步读取客户端请求消息到缓冲区,示例代码如下:
1 |
int readNumber = channel.read(receivedBuffer); |
步骤十:对ByteBuffer进行编解码,如果有半包消息指针reset,继续读取后续的报文,将解码成功的消息封装成Task,投递到业务线程池中,进行业务逻辑编排,示例代码如下:
01 |
Object message = null ; |
02 |
while (buffer.hasRemain()) |
05 |
Object message = decode(byteBuffer); |
11 |
messageList.add(message ); |
13 |
if (!byteBuffer.hasRemain()) |
17 |
if (messageList != null & !messageList.isEmpty()) |
19 |
for (Object messageE : messageList) |
20 |
handlerTask(messageE); |
步骤十一:将POJO对象encode成ByteBuffer,调用SocketChannel的异步write接口,将消息异步发送给客户端,示例代码如下:
1 |
socketChannel.write(buffer); |
注意:如果发送区TCP缓冲区满,会导致写半包,此时,需要注册监听写操作位,循环写,直到整包消息写入TCP缓冲区,此处不赘述,后续Netty源码分析章节会详细分析Netty的处理策略。
当我们了解创建NIO服务端的基本步骤之后,下面我们将前面的时间服务器程序通过NIO重写一遍,让大家能够学习到完整版的NIO服务端创建。
NIO服务端通信序列图