.NET Core 基於Websocket的線上聊天室
阿新 • • 發佈:2020-03-05
## 什麼是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