1. 程式人生 > >.NET Core 基於Websocket的線上聊天室

.NET Core 基於Websocket的線上聊天室

## 什麼是Websocket 我們在傳統的客戶端程式要實現實時雙工通訊第一想到的技術就是socket通訊,但是在web體系是用不了socket通訊技術的,因為http被設計成無狀態,每次跟伺服器通訊完成後就會斷開連線。 在沒有websocket之前web系統如果要做雙工通訊往往使用http long polling技術。http long polling 每次往伺服器傳送請求後,服務端不會立刻返回資訊來結束請求,而是一直掛著直到有資料需要返回,或者等待超時了才會返回。客戶端在結束上一次請求後立刻再發送一次請求,如此反覆。http long polling雖然能實現web系統的雙工通訊,但是有個很大的問題,就是基於http協議客戶端每次傳送請求都需要攜帶巨大的頭部。在併發互動少量資料的時候非常不划算,對伺服器資源的消耗也是巨大的。 websocket很好的改善了以上問題。它基於tcp重新設計了一套協議,同時又相容http,預設跟http一樣使用80/443埠。websocket連結建立本質上就是一次http請求,直接使用http協議的upgrade頭來標識這是一次websocket請求,服務端回覆101狀態碼錶示“握手”成功。 ``` //客戶端請求 GET / HTTP/1.1 Upgrade: websocket Connection: Upgrade Host: example.com Origin: http://example.com Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ== Sec-WebSocket-Version: 13 //服務端響應 HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s= Sec-WebSocket-Location: ws://example.com/ ``` ## 使用asp.net core來處理websocket 上面我們簡單的瞭解了websocket,那麼如何來使用asp.net core處理websocket呢?因為websocket的握手就是一次http請求,那麼我們就可以使用一個middleware來攔截websocket的請求,把建立的連結統一進行管理,其實微軟已經幫我們簡單的封裝過了。 ### 新建一個asp.net core網站 ![](https://images.cnblogs.com/cnblogs_com/kklldog/1401672/o_200304033211TIM%E6%88%AA%E5%9B%BE20200304105929.jpg) ### 新建WebsocketHandlerMiddleware中介軟體 這個中介軟體就是我們管理websocket連結的入口,我們呼叫context.WebSockets.AcceptWebSocketAsync()方法把請求轉換為websocket連結。 #### 在Invoke方法內接收websocket連結 ``` public async Task Invoke(HttpContext context) { if (context.Request.Path == "/ws") { if (context.WebSockets.IsWebSocketRequest) { WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(); string clientId = Guid.NewGuid().ToString(); ; var wsClient = new WebsocketClient { Id = clientId, WebSocket = webSocket }; try { await Handle(wsClient); } catch (Exception ex) { _logger.LogError(ex, "Echo websocket client {0} err .", clientId); await context.Response.WriteAsync("closed"); } } else { context.Response.StatusCode = 404; } } else { await _next(context); } } ``` #### 在Hanle方法等待客戶端的訊息 ``` private async Task Handle(WebsocketClient webSocket) { WebsocketClientCollection.Add(webSocket); _logger.LogInformation($"Websocket client added."); WebSocketReceiveResult result = null; do { var buffer = new byte[1024 * 1]; result = await webSocket.WebSocket.ReceiveAsync(new Arra