Nio實戰演練1(心跳服務)

2021-10-08 20:21:10 字數 3344 閱讀 5538

在類似rpc(遠端過程呼叫)場景中為了保證傳輸的效率,通常情況下會採用長鏈結,而長鏈結的保持即通過定時心跳實現。類似場景在訊息推送服務中也是非常常見。所以心跳服務是網路程式設計中的基礎且普遍的應用。

dubbo和zookpper都有心跳飽和機制

由客戶端定時傳送給服務端,服務端作出響應。因為一直要傳送,所以傳送的訊息和返回的訊息的體量必須足夠小,只要能標識心跳事件即可。具體訊息格式設計要根據所使用的應用協議而定。

在客戶端我們採用socketchannel來連線服務並註冊到選擇器,由選擇器來監聽管道的狀態並觸發相對應的事件處理。並通過執行緒休眠來實現,定時傳送。其整個流程如下圖

先初始化初始化管道,建立連線()。

連線遠端服務,在非阻塞模式,connect()是非同步完成的,當服務端accept鏈結,客戶端會觸發op_connect事件,然後必須呼叫 finishconnect() 才能真正完成呼叫。

socketchannel channel = socketchannel.

open()

;// 開啟管道

channel.

configureblocking

(false);

//設定非阻塞模型

selector selector = selector.

open()

;//開啟選擇器

channel.

register

(selector, selectionkey.op_connect)

;//監聽連線事件

註冊選擇器。

選擇器進行迴圈遍歷(基於對擇器的輪詢,就可以獲得選擇集,並觸發相對應事件)。

while

(true)}

}

循序操作首先呼叫select()重新整理鍵,重新整理鍵的時候會有三個事件

當服務端accept連線後,客戶端就會觸發op_connect事件。此時並不代表連線已完成,這時往管道中寫資料是會報notyetconnectedexception異常的。必須呼叫 finishconnect()才會真正建立好連線。當建立連線後,就不在需要監聽 op_connect,而是op_write事件,以將心跳事件資料寫入管道。

if

(key.

isconnectable()

)

什麼時候會觸發op_write 事件?當建立連線後管道就是乙個可寫狀態,所以直接就能觸發op_write事件。並且在關閉連線前op_write事件,一直會被觸發。所以寫入心跳後必須移除對op_write事件的監聽,改為監聽op_read事件。

if

(key.

isconnectable()

)

當服務端訊息返回客戶後就會觸發客戶端的op_read事件,此時直接讀取即可。然後在將執行緒休眠2s後切換監聽到op_write。如果不休眠會立馬觸發op_write事件。

channel.

read

(bytebuffer.

allocate(64

));key.

interestops

(selectionkey.op_write)

;thread.

sleep

(2000);

// 休眠2秒防止立馬進行寫入

因為是客戶端不是服務端沒有accpet

服務端流程說明

初始化管道

與客戶端類似 也是nio中常規操作,開啟管道與選擇器,設定阻塞然後註冊到選擇器。

這裡服務端使用serversocketchannel ,而客戶端使用socketchannel。兩者區別是serversocketchannel僅用於接受連線,不支援讀寫。而socketchannel用於連線和讀寫。

serversocketchannel serverlistener=serversocketchannel.

open()

;serverlistener.

bind

(new

inetsocketaddress

(8080))

;// 繫結tcp埠

serverlistener.

configureblocking

(false);

selector selector = selector.

open()

;// 註冊accept 事件,用於同意客戶端連線

serverlistener.

register

(selector,selectionkey.op_accept)

;

輪詢選擇器

請參照上面選擇器輪詢

觸發op_accept事件

op_accept指有新連線到達,通過serversocketchannel.accept() 即可獲取乙個新管道socketchannel。 基於它就可以與客戶端進行讀寫。這種讀寫同樣基於非阻塞方式執行,並註冊到選擇器。

if

(key.

isacceptable()

)

注:假設服務端接收的連線到達極限,是否可以直接勿略客戶端連線,不執行accept()方法?這是不行的,在tcp中所有事件都必須進行處理,否則會一直觸發該事件,造成死迴圈。

4. 觸發op_read事件

當客戶端傳送資料過來,即會觸發讀取事件,這時直接讀取即可,然後在寫回響應資料即可。

if

(key.

isreadable()

) buffer.

put(string.

valueof

(system.

currenttimemillis()

).getbytes()

);buffer.

flip()

; channel.

write

(buffer)

;// 寫回資料到管道

}

位元組』4』 在ascii中 表示eot (end of transmission )傳輸結束,所以在管道中讀取到4這個位元組,即可手動的去關閉連線。

演算法運用 KMP實戰演練

看完花名,滾來寫總結了。嗚嗚.題目 hdu1358 大意 求字串子串最大分割自我迴圈次數。表達的不好 解題 第一念頭想著用kmp兩層迴圈切割字串,第一層處理原串,第二層處理模式串。然後費了好大的勁寫了出來,結果,結果超時了 喂,這是理所應當的吧 沒辦法只好搜答案,發現只要運用next陣列就可以解決了...

《Python高效開發實戰》實戰演練 建立應用2

為了在專案中開發符合mvc架構的實際應用程式,需要在專案中建立django應用。每個django專案可以包含多個django應用。建立應用的語法為 應用名稱 cd djangosite命令完成後會在專案目錄中建立如下目錄及檔案結構 init py admin.py migrations init p...

iOS JSPatch熱更新之實戰演練

哈哈哈,希望上線的 永無bug,這樣就不用熱更新了。匯入需要的標頭檔案 require uilabel,uiimageview,nsurl,nsstring,uzgpersonalsetting,uiimage,uifont,uiscreen require uicolor defineclass ...