ASP.NET Web API上實現 Web Socket - 轉

1. 什麼是Web Sockethtml

Web Socket是Html5中引入的通訊機制,它爲瀏覽器與後臺服務器之間提供了基於TCP的全雙工的通訊通道。用以替代以往的LongPooling等comet style的實時解決方案。基於它們之間的比較以及Web Socket的優點參考https://www.websocket.org/quantum.html.git

2. Web Socket如何工做github

Connectweb

Web Socket在創建以前須要先與後臺服務器進行握手。具體來講經過以下Http請求:api

複製代碼
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com
複製代碼

後臺服務器若是支持切換到WebSocket,會返回以下Response:瀏覽器

HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat

瀏覽器收到該Response會切換到基於當前TCP鏈接的WebSocket通道。服務器

Data Transferwebsocket

鏈接創建後,瀏覽器端能夠和服務器發送Text類型的消息進行全雙工的通訊,相似於基於TCP的Socket通訊。異步

Disconnectsocket

當瀏覽器或者後臺服務器想終止通訊,需向對方發送類型爲Close的消息,並等待對方收到消息並確認後鏈接斷開。

3. 瀏覽器,服務器支持狀況

參考維基百科,目前瀏覽器的支持狀況以下:

IE Chrome Firefox Safari Opera    
10+ 16+ 11+ 6+ 12.10+    

 

 

 

IIS從8.0開始支持Web Socket

好了,很長的鋪墊以後正式進入Coding:

1. 爲了接受瀏覽器端的握手請求,咱們須要定義一個Web Api接口接受握手請求

複製代碼
[RoutePrefix("api/chat")]
    public class ChatController : ApiController
    {
        private static List<WebSocket> _sockets = new List<WebSocket>();

        [Route]
        [HttpGet]
        public HttpResponseMessage Connect(string nickName)
        {
            HttpContext.Current.AcceptWebSocketRequest(ProcessRequest); //在服務器端接受Web Socket請求,傳入的函數做爲Web Socket的處理函數,待Web Socket創建後該函數會被調用,在該函數中能夠對Web Socket進行消息收發

            return Request.CreateResponse(HttpStatusCode.SwitchingProtocols); //構造贊成切換至Web Socket的Response.
        }
    }
複製代碼

2. 爲了對Web Socket進行消息收發,須要定義Web Socket的消息收發函數(之前的.net 版本是接受一個實現特定接口的對象,新版改爲了接受一個函數,總以爲怪怪的),代碼以下:

複製代碼
public async Task ProcessRequest(AspNetWebSocketContext context)
      {
            var socket = context.WebSocket;//傳入的context中有當前的web socket對象
            _sockets.Add(socket);//此處將web socket對象加入一個靜態列表中

       //進入一個無限循環,當web socket close是循環結束 while (true) { var buffer = new ArraySegment<byte>(new byte[1024]); var receivedResult = await socket.ReceiveAsync(buffer, CancellationToken.None);//對web socket進行異步接收數據 if (receivedResult.MessageType == WebSocketMessageType.Close) { await socket.CloseAsync(WebSocketCloseStatus.Empty, string.Empty, CancellationToken.None);//若是client發起close請求,對client進行ack _sockets.Remove(socket); break; } if (socket.State == System.Net.WebSockets.WebSocketState.Open) { string recvMsg = Encoding.UTF8.GetString(buffer.Array, 0, receivedResult.Count); var recvBytes = Encoding.UTF8.GetBytes(recvMsg); var sendBuffer = new ArraySegment<byte>(recvBytes); foreach (var innerSocket in _sockets)//當接收到文本消息時,對當前服務器上全部web socket鏈接進行廣播 { if (innerSocket != socket) { await innerSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None); } } } }
複製代碼

服務器端代碼就緒,瀏覽器端如何去調用呢,繼續看代碼:

複製代碼
var webSocket = new WebSocket("ws://localhost/api/chat?nickName=" + nickName.value);
    webSocket.onopen = function () {
        console.log("opened");
    }
    webSocket.onerror = function () {
        console.log("web socket error");
    }

    webSocket.onmessage = function (event) {
    console.log("web socket error");
 } 

self.webSocket.onclose = function () { console.log("closed"); }
複製代碼

這樣就創建了一個web socket鏈接並能收到消息了,固然也會有發送消息的接口:

webSocket.send(「Hello Web Socket」);

到這裏,基於web socket的全雙工通訊機制已經創建好了。文中的demo是一個簡易的聊天室程序。代碼連接:https://github.com/lbwxly/WebSocketSample

補充:

HttpContext的AcceptWebSocketRequest方法只能接受一個函數確實有點不方便,也不利於封裝與複用。所以爲其添加了一個接受對象的重載extension方法,而後定義一個類WebSocketHandler來處理消息的收發和鏈接的關閉。詳見上面的代碼連接。

相關文章
相關標籤/搜索