建立與使用WebSocket API

by Vivid 10. 四月 2013 03:17

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:N130413501
出刊日期:2013/4/10

WebSocket API定義WebSocket物件以便用來建立用戶端應用程式與伺服端之間的連線。用戶端可以透過WebSocket物件提供的方法連接到伺服端,傳送文字格式、二進位格式、JSON格式訊息或陣列資料到伺服端;也可以接收伺服端傳送過來的訊息。WebSocket API是雙向的,伺服端可以視需要,隨時傳送訊息到用戶端。同時WebSocket物件也提供一些屬性,例如readyState,可用於判斷連線目前的狀態。

本文介紹如何使用WebSocket API來撰寫用戶端的程式碼,以及ASP.NET 4.5 與IIS 8新增的WebSocket支援,讓您可以自行撰寫伺服端的Web Socket程式碼。

坊間有許多現成的WebSocket伺服端可以使用,不一定要自行撰寫伺服端的程式碼,我們先從用戶端瀏覽器的程式碼談起。

 

判斷支援度

若瀏覽器支援WebSocket,您便可以透過window物件的WebSocket屬性來取得WebSocket物件,因此你可以利用以下JavaScript程式碼片斷來判斷瀏覽器的支援度:

 

if ( window.WebSocket ) {
   alert( "瀏覽器支援 WebSocket" );
} else {
   alert( "瀏覽器不支援 WebSocket " );
}

 

 

開啟與關閉連線

用戶端要跟WebSocket伺服器溝通的第一步便是建立連線,建立WebSocket物件時,可以透過建構函式傳入WebSocket伺服器的所在URL位址。URL位址使用ws或wss(SSL) scheme開始,參考以下URL範例:

 

ws://localhost:26462/WSHandler.ashx

接著scheme之後的是主機名稱(本例為localhost),再來是埠號(26462,選擇性的,若省略則預設為80埠),以及WebSocket伺服器(WSHandler.ashx),本例使用ASP.NET 4.5提供的新功能自行實作了WebSocket伺服器-WSHandler.ashx,這部分稍後再述。

以下JavaScript程式片段建立一個WebSocket物件,並在建構函式傳入WebSocket伺服器位址,預設此行程式碼會透過HTTP自動和伺服器溝通,伺服器若接收用戶端的請求,則透過TCP協定來建立一個連線:

var socket = new WebSocket( "ws://localhost:26462/WSHandler.ashx" );

建立連線之後,您可以利用open、message與close等等事件來撰寫和伺服端溝通的程式碼。open事件是在連線建立成功之後觸發,以下JavaScript程式片斷註冊open事件,若事件觸發,可由WebSocket物件的readyState屬性來判斷連線狀態:

 

var socket = new WebSocket( "ws://localhost:26462/WSHandler.ashx" );
socket.onopen = function ( ) {
  alert( "建立與伺服端的連線!  state : " + socket.readyState );
  socket.send( "Hi" );
  alert(" 訊息已傳送..." );
  socket.close();
  alert( "關閉socket ...,  state : " + socket.readyState );
};

 

readyState屬性的值可以是

· CONNECTING:數值0,表示已建立WebSocket物件,正在連結到伺服器中。
· OPEN:數值1,連線已建立。
· CLOSING:數值2,連線正在關閉中。
· CLOSED:數值3,連線已關閉。

WebSocket建立之後,便可以叫用WebSocket物件的send方法來傳送訊息到伺服端,它會以非同步的方式來執行。send方法可以傳送的文字類型資訊包含UTF8格式文字、純文字、json格式字串,或base64編碼的字串。

若要關閉用戶端與伺服端的連線,便可以叫用close()方法。

 

error事件

若連線到伺服端的過程中發生錯誤,可以註冊error事件,從event物件的data屬性可以取得錯誤相關資訊。error事件會比close事件還要早發生。參考以下JavaScript程式碼片段:

 

socket.onerror = function ( event ) {
        alert( "發生錯誤 : " + event.data );
      }

 

接收WebSocket訊息

若要在用戶端接收WebSocket伺服端傳送過來的訊息,可以攔截message事件,此事件在接收到伺服端傳送過來的訊息到達時觸發。以下JavaScript程式範例,利用event物件的data屬性取出由伺服端傳送來的資訊:

 

socket.onmessage = function ( event ) {
  var msg = event.data;
  alert( "已收到伺服器傳送的訊息..." + msg );
};

 

WebSocket程式範例

完整的WebSocket程式範例列表如下:

 

<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv = "Content-Type" content = "text/html; charset=utf-8" />
  <title> WebSocket Demo</title>
  <script type = "text/javascript" >
    function contentLoaded( ) {
      if ( window.WebSocket ) {
        alert( "瀏覽器支援 WebSocket" );
      } else {
        alert( "瀏覽器不支援 WebSocket " );
      }
    }
    function openSocket( ) {
      var socket = new WebSocket( "ws://localhost:26462/WSHandler.ashx" );
      socket.onopen = function ( ) {
        alert( "建立與伺服端的連線!  state : " + socket.readyState );
        socket.send( "Hi" );
        alert( "訊息已傳送..." );
      };

      socket.onmessage = function ( event ) {
             var msg = event.data;
          alert( "已收到伺服器傳送的訊息..." + msg );
      };
      socket.onclose = function ( event ) {
        alert( "連線已關閉... state :" + socket.readyState );    
      };
      socket.onerror = function ( event ) {
        alert( "發生錯誤 : " + event.data );
      };
    }
    window.addEventListener( "DOMContentLoaded", contentLoaded , false );
  </script>
</head>
<body>
  <input id = "Button1" type = "button" value =" Connect to Server" onclick="openSocket()" />
</body>
</html>

 

使用ASP.NET撰寫伺服端WebSocket程式

在Windows 8或Windows Server 2012內建支援WebSocket的功能,可以利用HTTP請求,建立以WebSocket為基礎的雙向通訊機制。預設IIS 8 Express便可以直接使用WebSocket;若使用Windows 8或Windows Server 2012作業系統上的IIS 8,則需要透過作業系統新增WebSocket通訊協定的功能,從作業系統「控制台」-「所有控制台項目」-「程式和功能」-「開啟或關閉Windows 功能」-「Internet Information Services」-「World Wide Web服務」-「應用程式開發功能」-勾選「WebSocket通訊協定」,請參考下圖所示:

clip_image001

圖 1:新增「WebSocket通訊協定」功能。

任何用戶端程式都支援WebSocket協定,不跼限於瀏覽器;以微軟的技術而論,伺服端則於ASP.NET 4.5版新增System.Web.WebSockets與System.Net.WebSockets兩個命名空間,提供許多類別來支援WebSocket。

在Visual Studio 2012,ASP.NET網站類型的專案中,可以加入「泛型處理常式」範本來撰寫WebSocket伺服端程式,請參考下圖所示:

clip_image003

圖 2:使用「泛型處理常式」範本來撰寫WebSocket伺服端程式。

WebSocket伺服端程式如下:

<%@ WebHandler Language = "C#" Class = "WSHandler" %>
using System;
using System.Web;
using System.Threading.Tasks;
using System.Web.WebSockets;
using System.Net.WebSockets;
using System.Text;
using System.Threading;

public class WSHandler : IHttpHandler {
  public void ProcessRequest( HttpContext context ) {
    if ( context.IsWebSocketRequest )
      context.AcceptWebSocketRequest(  MyWebSocketHandler );
    else
      context.Response.StatusCode = 400; //Bad Request
  }

  public async Task MyWebSocketHandler( AspNetWebSocketContext context ) {
    WebSocket socket = context.WebSocket;
    while ( true ) {
      ArraySegment<byte> buffer = new ArraySegment<byte>( new byte[ 2048 ] );
      WebSocketReceiveResult r =
              await socket.ReceiveAsync( buffer , CancellationToken.None );

      if ( socket.State == WebSocketState.Open ) {
        string msg = Encoding.UTF8.GetString( buffer.Array , 0 , r.Count );
        msg = "伺服端收到你傳送的訊息 : " + msg;

        buffer = new ArraySegment<byte>( Encoding.UTF8.GetBytes( msg ) );
        await socket.SendAsync( buffer , WebSocketMessageType.Text ,
                true , CancellationToken.None );
      }
    }
  }
  public bool IsReusable {
    get {
      return false;
    }
  }
}

 

在ProcessRequest方法中,利用HttpContext物件的IsWebSocketRequest屬性來判斷目前接收到的請求是否是一個AspNetWebSocket請求,若為是,且IIS 8的WebSocket通訊協定正確安裝且設定之後,IsWebSocketRequest屬性值就會是true。這時我們就可以叫用HttpContext物件的AcceptWebSocketRequest方法接收請求,並指定透過MyWebSocketHandler方法以非同步方式做後續處理。

MyWebSocketHandler方法是一個非同步的方法,因此方法宣告中使用async關鍵字加以宣告。在此方法中使用WebSocket物件的ReceiveAsync方法以非同步方式接收用戶端傳來的訊息。ReceiveAsync方法前方需要標示await關鍵字。

若要傳送資料到用戶端,可以叫用非同步的SendAsync方法,並將要傳送的訊息包裝成一個ArraySegment<byte>物件傳入SendAsync方法第一個參數。

 

參考資料:

· What's New in ASP.NET 4.5 and Visual Studio 2012 http://www.asp.net/vnext/overview/aspnet/whats-new#_Toc318097383

Tags:

.NET Magazine國際中文電子雜誌 | ASP.NET | HTML | 許薰尹Vivid Hsu

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List