天天看點

《Netty 權威指南》—— 服務端序列圖

聲明:本文是《netty 權威指南》的樣章,感謝博文視點授權并發程式設計網站釋出樣章,禁止以任何形式轉載此文。

下面,我們對nio服務端的主要建立過程進行講解和說明,作為nio的基礎入門,我們将忽略掉一些在生産環境中部署所需要的一些特性和功能。

步驟一:打開serversocketchannel,用于監聽用戶端的連接配接,它是所有用戶端連接配接的父管道,代碼示例如下:

<code>1</code>

<code>serversocketchannel acceptorsvr = serversocketchannel.open();</code>

步驟二:綁定監聽端口,設定連接配接為非阻塞模式,示例代碼如下:

<code>acceptorsvr.socket().bind(</code><code>new</code> <code>inetsocketaddress(inetaddress.getbyname(“ip”), port));</code>

<code>2</code>

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

步驟三:建立reactor線程,建立多路複用器并啟動線程,代碼如下:

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

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

步驟四:将serversocketchannel注冊到reactor線程的多路複用器selector上,監聽accept事件,代碼如下:

<code>selectionkey key = acceptorsvr.register( selector, selectionkey.op_accept, iohandler);</code>

步驟五:多路複用器線上程run方法的無限循環體内輪詢準備就緒的key,代碼如下:

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

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

<code>3</code>

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

<code>4</code>

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

<code>5</code>

<code>     </code><code>selectionkey key = (selectionkey)it.next();</code>

<code>6</code>

<code>     </code><code>// ... deal with i/o event ...</code>

<code>7</code>

<code>}</code>

步驟六:多路複用器監聽到有新的用戶端接入,處理新的接入請求,完成tcp三次握手,建立實體鍊路,代碼示例如下:

<code>socketchannel channel = svrchannel.accept();</code>

步驟七:設定用戶端鍊路為非阻塞模式,示例代碼如下:

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

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

步驟八:将新接入的用戶端連接配接注冊到reactor線程的多路複用器上,監聽讀操作,用來讀取用戶端發送的網絡消息,代碼如下:

<code>selectionkey key = socketchannel.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>{</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>else</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>

注意:如果發送區tcp緩沖區滿,會導緻寫半包,此時,需要注冊監聽寫操作位,循環寫,直到整包消息寫入tcp緩沖區,此處不贅述,後續netty源碼分析章節會詳細分析netty的處理政策。

當我們了解建立nio服務端的基本步驟之後,下面我們将前面的時間伺服器程式通過nio重寫一遍,讓大家能夠學習到完整版的nio服務端建立。

《Netty 權威指南》—— 服務端序列圖

nio服務端通信序列圖

繼續閱讀