天天看点

《Netty 权威指南》—— NIO客户端序列图

步骤一:打开socketchannel,绑定客户端本地地址(可选,默认系统会随机分配一个可用的本地地址),示例代码如下:

<code>1</code>

<code>socketchannel clientchannel = socketchannel.open();</code>

步骤二:设置socketchannel为非阻塞模式,同时设置客户端连接的tcp参数,示例代码如下:

<code>clientchannel.configureblocking(</code><code>false</code><code>);</code>

<code>2</code>

<code>socket.setreuseaddress(</code><code>true</code><code>);</code>

<code>3</code>

<code>socket.setreceivebuffersize(buffer_size);</code>

<code>4</code>

<code>socket.setsendbuffersize(buffer_size);</code>

步骤三:异步连接服务端,示例代码如下:

<code>boolean</code> <code>connected = clientchannel.connect(</code><code>new</code> <code>inetsocketaddress(“ip”,port));</code>

步骤四:判断是否连接成功,如果连接成功,则直接注册读状态位到多路复用器中,如果当前没有连接成功(异步连接,返回false,说明客户端已经发送sync包,服务端没有返回ack包,物理链路还没有建立),示例代码如下:

<code>if</code> <code>(connected)</code>

<code>{</code>

<code>    </code><code>clientchannel.register( selector, selectionkey.op_read, iohandler);</code>

<code>}</code>

<code>5</code>

<code>else</code>

<code>6</code>

<code>7</code>

<code>    </code><code>clientchannel.register( selector, selectionkey.op_connect, iohandler);</code>

<code>8</code>

步骤五:向reactor线程的多路复用器注册op_connect状态位,监听服务端的tcp ack应答,示例代码如下:

<code>clientchannel.register( selector, selectionkey.op_connect, iohandler);</code>

步骤六:创建reactor线程,创建多路复用器并启动线程,代码如下:

<code>selector selector = selector.open();</code>

<code>new thread(</code><code>new</code> <code>reactortask()).start();</code>

步骤七:多路复用器在线程run方法的无限循环体内轮询准备就绪的key,代码如下:

<code>int</code> <code>num = selector.select();</code>

<code>set selectedkeys = selector.selectedkeys();</code>

<code>iterator it = selectedkeys.iterator();</code>

<code>while</code> <code>(it.hasnext()) {</code>

<code>if</code> <code>(key.isconnectable())</code>

<code>  </code><code>//handlerconnect();</code>

步骤九:判断连接结果,如果连接成功,注册读事件到多路复用器,示例代码如下:

<code>if</code> <code>(channel.finishconnect())</code>

<code>  </code><code>registerread();</code>

步骤十:注册读事件到多路复用器:

<code>clientchannel.register( selector, selectionkey.op_read, iohandler);</code>

步骤十一:异步读客户端请求消息到缓冲区,示例代码如下:

<code>int</code>  <code>readnumber =  channel.read(receivedbuffer);</code>

步骤十二:对bytebuffer进行编解码,如果有半包消息接收缓冲区reset,继续读取后续的报文,将解码成功的消息封装成task,投递到业务线程池中,进行业务逻辑编排,示例代码如下:

<code>01</code>

<code>object message = </code><code>null</code><code>;</code>

<code>02</code>

<code>while</code><code>(buffer.hasremain())</code>

<code>03</code>

<code>04</code>

<code>       </code><code>bytebuffer.mark();</code>

<code>05</code>

<code>       </code><code>object message = decode(bytebuffer);</code>

<code>06</code>

<code>       </code><code>if</code> <code>(message == </code><code>null</code><code>)</code>

<code>07</code>

<code>       </code><code>{</code>

<code>08</code>

<code>          </code><code>bytebuffer.reset();</code>

<code>09</code>

<code>          </code><code>break</code><code>;</code>

<code>10</code>

<code>       </code><code>}</code>

<code>11</code>

<code>       </code><code>messagelist.add(message );</code>

<code>12</code>

<code>13</code>

<code>if</code> <code>(!bytebuffer.hasremain())</code>

<code>14</code>

<code>bytebuffer.clear();</code>

<code>15</code>

<code>16</code>

<code>    </code><code>bytebuffer.compact();</code>

<code>17</code>

<code>if</code> <code>(messagelist != </code><code>null</code> <code>&amp; !messagelist.isempty())</code>

<code>18</code>

<code>19</code>

<code>for</code><code>(object messagee : messagelist)</code>

<code>20</code>

<code>   </code><code>handlertask(messagee);</code>

<code>21</code>

步骤十三:将pojo对象encode成bytebuffer,调用socketchannel的异步write接口,将消息异步发送给客户端,示例代码如下:

<code>socketchannel.write(buffer);</code>

通过序列图和关键代码的解说,相信大家对创建nio客户端程序有了一个初步的了解,下面,就跟随着我们的脚步继续看看如果使用nio改造之前的时间服务器客户端timeclient。

《Netty 权威指南》—— NIO客户端序列图

nio客户端创建序列图

继续阅读