Magician 是一個異步非阻塞的網絡編程包,用java語言實現,支持Http, WebSocket, UDP等協議
運行環境
jdk11+
簡單的原理介紹
Magician的底層使用的是NIO,但是沒有用Selector,因爲Selector的設計初衷就是爲了用單線程來處理高併發,從而減少 因爲連接太多而造成線程太多,佔用過多的服務器資源。 但是這樣做的壞處也很明顯,就是無法充分利用cpu的多核性能,還有一個就是 如果業務比較耗時,會造成整個循環被堵住。
所以,考慮到這一點,Magician決定使用accept,代碼如下:
while (true){
SocketChannel channel = null;
try {
/* 這個方法會阻塞,直到有新連接進來 */
channel = serverSocketChannel.accept();
channel.configureBlocking(false);
/* 將任務添加到隊列裏執行 */
ParsingThreadManager.addTaskToParsingThread(channel);
} catch (Exception e){
logger.error("處理請求出現異常", e);
ChannelUtil.close(channel);
}
}
有一個while不斷的監聽accept,當沒有新請求進來的時候accept是阻塞的,所以不會有空輪詢的問題,當有了新的請求進來,就會把channel丟到隊列裏面去,然後繼續監聽accept。
那麼這個隊列是什麼結構的?他又是如何來執行的呢?
首先,隊列的結構是這樣的:他是一個LinkedBlockingDeque,有序 且 長度無限(除非內存爆了),然後這個隊列 放在了一個線程中, 線程開啓後就會有一個while 不斷的從這個隊列裏take 元素,如果隊列爲空,take就會阻塞,隊列一旦有數據 take就會按順序返回裏面的元素。
所以,只要這個線程在運行,我們就可以不斷的往隊列裏丟任務,讓這個線程來慢慢消化。
如果這樣的線程+隊列有多個, 我們把收到的請求 通過輪詢算法 分配到這些隊列,讓線程各自消化,是不是就可以實現一個,線程數量可控,同時又具有異步特性的模型?
這個模型就是Magician現在所使用的,如下圖所示:
在使用Magician的時候,可以自己配置 需要幾個線程來同時運行。
除了http,udp也是採用的這個模型。只不過udp是以同步的模式讀數據,數據讀完了 再丟到隊列裏 讓隊列去執行業務邏輯。
如何使用
說了這麼多原理,我們接下來說說 如何使用Magician來開發各種服務。
首先我們看一下http的實現
Magician.createHttpServer().httpHandler("/", req -> {
req.getResponse()
.sendJson(200, "{'status':'ok'}");
}).bind(8080).start();
如果不想把handler 跟這段代碼窩在一起,可以單獨建立handler,在這裏添加進去即可
WebSocket實現
Magician.createHttpServer().bind(8080)
.httpHandler("/", new DemoHandler())
.webSocketHandler("/websocket", new DemoSocketHandler())
.start();
只需要在創建http服務的時候,添加一個WebSocketHandler即可。
UDP實現
Magician.createUdpServer()
.handler(outputStream -> {
// outputStream 是ByteArrayOutputStream類型的
// 它是客戶端發過來的數據,自行解析即可
}).bind(8088).start();
同樣的,也可以單獨創建handler,在這裏添加進去
瞭解更多
想了解更多的話,歡迎訪問Magician官網:http://magician-io.com