專業挖坑21年
1.前 言
網上找了很多資料,可能是自己找的路子不對吧,都找不到適合我這樣萌新的文章,大多.net環境使用的websocket都是在說一個通信的案例,學起來的確很吃力,自己也挖坑很久才爬出來,所以本篇文章也只是對自己學習的做一個總結。
2.為什么需要WebSocket
在已經存在http協議的情況下還使用其他協議?
HTTP協議:通信只能是客戶端發起,做不到服務器主動向客戶端推送信息,以前使用輪詢方式請求服務器(浪費資源、效率低)
Websocket就是在這樣的環境下發明的,在阮一峰老師文章中講解很詳細
http://www.ruanyifeng.com/blog/2017/05/websocket.html
3.websocket怎樣建立連接
首先客戶端需要和服務端達成握手的協議
客戶端
向服務器發起連接
1 webSocket = new WebSocket("ws://localhost/api/chat");
服務端
代碼不完整只加入了接收的代碼
[Route] [HttpGet] public HttpResponseMessage Connect(string nickName) { //在服務端接受web socket請求,傳入的函數作為web socket的處理函數,待web socket建立后該函數會被調用, //在該函數中可以對web socket進行消息收發 HttpContext.Current.AcceptWebSocketRequest(ProcessRequest);//將websocket接受到AspNetWebSocketContext //構造同意切換至web socket的response return Request.CreateResponse(HttpStatusCode.SwitchingProtocols); } public async Task ProcessRequest(AspNetWebSocketContext context) { var socket = context.WebSocket;//傳入的context中當前的web socket對象 }
4.客戶端的API
Websocket給了幾個回調函數,其他的API我就不一一列出了,阮老師的文章中寫的很詳細
//建立成功 webSocket.onopen = function () { console.log("socket opened"); } //異常 webSocket.onerror = function () { console.log("An exception hai occurred"); } //服務端返回消息回調 webSocket.onmessage = function (event) { console.log(event.data); } //關閉連接回調 webSocket.onclose = function () { console.log("socket closed"); } //向服務器發送數據 webSocket.send("hellow word");
//客戶端主動斷開連接 webSocket.close();
5.關於服務端
服務端建立連接之后作為一個初學者來說我想知道是怎樣實現和客戶端進行進行會話
接收:
// // 摘要: // 從 WebSocket 連接異步接受數據。 // // 參數: // buffer: // 引用應用程序緩沖區,其為接收的數據的存儲位置。 // // cancellationToken: // 傳播有關應取消操作的通知。 // // 返回結果: // 返回 System.Threading.Tasks.Task`1。表示異步操作的任務對象。任務對象上的 System.Threading.Tasks.Task`1.Result // 屬性將返回包含已接收數據的 System.Byte 數組。 public abstract Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer, CancellationToken cancellationToken);
發送:
// // 摘要: // 發送 WebSocket 上連接異步的數據。 // // 參數: // buffer: // 要通過連接發送的緩沖區。 // // messageType: // 指示應用是否發送二進制或文本消息。 // // endOfMessage: // 指示在“緩沖區”的數據是否實消息的最后一部分。 // // cancellationToken: // 傳播有關應取消操作的通知的標記。 // // 返回結果: // 返回 System.Threading.Tasks.Task。表示異步操作的任務對象。 public abstract Task SendAsync(ArraySegment<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken);
其實整個過程就幾句代碼,但是一直找不到適合我自己的,走了很多彎路,最后把寫的案例代碼貼上來(雖然是看着別人的寫的)
6.案例代碼
客戶端
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> <div> <input id="nickName" name="nickName" type="text" value="Jone" /> </div> <div> <input id="btnConnection" name="btnConnection" value="Connection" type="button" /> <input id="btnDisconnect" name="btnDisconnect" value="Disconnect" type="button" /> </div> <div> <input id="btnSend" name="btnSend" value="Send" type="button" /> </div> <div id="message"> </div> </body> </html>
<script> window.onload = function () { document.getElementById("btnConnection").onclick = Connection; document.getElementById("btnDisconnect").onclick = Disconnect; document.getElementById("btnSend").onclick = Send; //CreateWebSocket("ws://localhost/WebApiDemo/api/chat?nickName=b4s51x2"); } var webSocket; function Connection() { webSocket = new WebSocket("ws://localhost/WebApiDemo/api/chat?nickName=b4s51x2"); InitEventHandles(); } function InitEventHandles() { //建立成功 webSocket.onopen = function () { console.log("socket opened"); } //異常 webSocket.onerror = function () { console.log("An exception hai occurred"); } //服務端返回消息回調 webSocket.onmessage = function (event) { console.log(event.data); } //關閉連接回調 webSocket.onclose = function () { console.log("socket closed"); } } function Send() { //向服務器發送數據 webSocket.send(document.getElementById("nickName").value); } function Disconnect() { webSocket.close(); } </script>
服務端
private static List<WebSocket> _socket = new List<WebSocket>();
[Route] [HttpGet] public HttpResponseMessage Connect(string nickName) { //在服務端接受web socket請求,傳入的函數作為web socket的處理函數,待web socket建立后該函數會被調用, //在該函數中可以對web socket進行消息收發 HttpContext.Current.AcceptWebSocketRequest(ProcessRequest); //構造同意切換至web socket的response return Request.CreateResponse(HttpStatusCode.SwitchingProtocols); } public async Task ProcessRequest(AspNetWebSocketContext context) { var socket = context.WebSocket;//傳入的context中當前的web socket對象 _socket.Add(socket);//此處將web socket對象加入一個靜態列表中 //進入一個無限循環,當web socket close是循環結束 while (true) { var buffer = new ArraySegment<byte>(new byte[1024]); var receviedResult = await socket.ReceiveAsync(buffer, CancellationToken.None);//對web socket進行異步接收數據 if (receviedResult.MessageType == WebSocketMessageType.Close) { await socket.CloseAsync(WebSocketCloseStatus.Empty, string.Empty, CancellationToken.None);//如果client發起close請求,對client進行ack _socket.Remove(socket); break; } if (socket.State == WebSocketState.Open) { string recvMsg = Encoding.UTF8.GetString(buffer.Array, 0, receviedResult.Count); var recvBytes = Encoding.UTF8.GetBytes(recvMsg); var sendBuffer = new ArraySegment<byte>(recvBytes); foreach (var innerSocket in _socket)//當接收到文本消息時,對當前服務器上所有web socket鏈接進行廣播 { if (innerSocket == socket) { await innerSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None); } } } } }
服務端原文章找不到了,最后感謝各位大佬提供的文章學習。

