.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:N130413502
出刊日期:2013/4/24
在前一篇文章中介紹了HTML5 WebSocket API基本呼叫方式,在JavaScript中定義WebSocket物件建立用戶端應用程式與伺服端之間的連線,並傳送文字格式到伺服端ASP.NET網站,同時ASP.NET網頁收到請求之後,回應文字格式的訊息。除了傳送文字格式的訊息之外,WebSocket也可以,傳送二進位格式、JSON格式訊息或陣列資料到伺服端。本文介紹如何使用HTML5 WebSocket API進行在用戶端與伺服端之間,進行各種資料格式的交換動作。
WebSocket協定
回顧前文提及的WebSocket協定,它可使用雙工方式,讓瀏覽器和Web伺服器進行即時通訊。建立WebSocket連線,在初化階段用戶端與伺服端就從使用HTTP協定,自動升級轉換改用WebSocket協定。
例如底下是使用Chrome瀏覽器觀察WebSocket呼叫結果,瀏覽器以HTTP GET方式傳送請求給WebSocket伺服端程式,建立連線之後,後續會改用Transmission Control Protocol (TCP) socket協定進行通訊。

圖 1:瀏覽器與伺服端自動升級轉換改用WebSocket協定。
WebSocket可以傳送的文字類型資訊包含UTF8格式文字、純文字、JSON格式字串,或base64編碼的字串,以下將探討如何交換這些不同格式的資料。
傳送ArrayBuffer物件
ArrayBuffer表示一個緩衝區,用於存放二進位資料,您可以利用Uint8Array或Int32Array來取得ArrayBuffer物件。Uint8Array或Int32Array都是屬於具型別陣列(Typed Array),分別存放8位元(bit) 不帶正負號整數值,以及32位元帶正負號的整數值。Uint8Array值的有效範圍為0~255;Int32Array值的有效範圍為-2147483648到2147483647。預設陣列中的成員會被初始化為0。
傳送Uint8Array範例
以下範例程式在建立連線,觸發Websocket的open事件時,建立一個Uint8Array陣列,送出8位元不帶正負號的整数(unsigned integer)陣列到Websocket伺服端進行加總。並在message事件中將伺服端計算完的結果取回顯示在網頁畫面上:
<!DOCTYPE html>
<html xmlns = "
http://www.w3.org/1999/xhtml" >
<head>
<meta http-equiv = "Content-Type" content = "text/html; charset=utf-8" />
<title> </title>
<script type = "text/javascript">
function openSocket ( ) {
var socket = new WebSocket( "ws://localhost:26462/WSHandler1.ashx" );
socket.onopen = function () {
var numbers = new Uint8Array( [10, 20, 30, 40, 50, 60, 70, 80, 90] );
socket.send( numbers.buffer );
alert( "訊息已傳送..." );
};
socket.onmessage = function ( event ) {
var msg = event.data;
document.getElementById( "result" ).innerHTML = "已收到伺服器傳送的訊息 : " + msg;
};
socket.onclose = function ( event ) {
alert( "連線已關閉... state :" + socket.readyState );
};
socket.onerror = function ( event ) {
alert( "發生錯誤 : " + event.data );
};
}
</script>
</head>
<body>
<input id = "Button1" type = "button" value = "Connect to Server" onclick = "openSocket()" />
<div id = "result"> </div>
</body>
</html>
伺服端的程式如下,收到資料之後利用一個迴圈,將接收到的位元陣列內容取出之後進行加總,最後再將運算結果傳回用戶端:
<%@ 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 [ 1024 ] );
WebSocketReceiveResult r = await socket.ReceiveAsync( buffer , CancellationToken.None );
if ( socket.State == WebSocketState.Open )
{
int total = 0;
for ( int i = 0 ; i < buffer.Array.Length ; i++ )
{
total += buffer.Array [ i ];
}
string msg = total.ToString( );
msg = "伺服端收到你傳送的訊息 : " + msg + " 時間 : " + DateTime.Now.ToString( );
buffer = new ArraySegment<byte>( Encoding.UTF8.GetBytes( msg ) );
await socket.SendAsync( buffer , WebSocketMessageType.Text , true , CancellationToken.None );
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
此網頁範例執行的結果,請參考下圖所示:

圖 2:傳送Uint8Array陣列範例。
傳送Uint32Array範例
若用戶端傳送的是Uint32Array,例如將上一個範例open事件的程式碼修改如下:
socket.onopen = function ( ) {
alert( "建立與伺服端的連線! state :" + socket.readyState );
var numbers = new Uint32Array( [-10,-20,-30, -40, 50, 60, 70, 80, 90] );
socket.send( numbers.buffer );
alert( "訊息已傳送..." );
};
則伺服端收到資料時,需要加上一些程式碼,將32位元的資料轉換成數值。每一個數值的資料以四個位元組組成,例如第一個「-10」的值送到伺服端時,伺服端的buffer.Array前四個項目的內容分別為「246、255、255、255」,我們可以利用BitConverter.ToInt32方法將其轉換回「-10」:
<%@ 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 [ 1024 ] );
WebSocketReceiveResult r = await socket.ReceiveAsync( buffer , CancellationToken.None );
if ( socket.State == WebSocketState.Open )
{
var len = buffer.Array.Length;
int [ ] data = new int [ len / 4 ];
var idx = 0;
for ( int i = 0 ; i < len ; i += 4 )
{
byte [ ] number = { buffer.Array [ i ] , buffer.Array [ i + 1 ] , buffer.Array [ i + 2 ] , buffer.Array [ i + 3 ] };
data [ idx ] = BitConverter.ToInt32( number , 0 );
idx++;
}
int total = 0;
for ( int i = 0 ; i < data.Length ; i++ )
{
total += data [ i ];
}
string msg = total.ToString( );
msg = "伺服端收到你傳送的訊息 : " + msg + " 時間 : " + DateTime.Now.ToString( );
buffer = new ArraySegment<byte>( Encoding.UTF8.GetBytes( msg ) );
await socket.SendAsync( buffer , WebSocketMessageType.Text , true , CancellationToken.None );
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
此網頁範例執行的結果,請參考下圖所示:

圖 3:傳送Uint32Array範例。
傳送字串陣列範例
若用戶端傳送的是字串陣列,例如將上一個範例open事件的程式碼修改如下:
socket.onopen = function () {
alert( "建立與伺服端的連線! state :" + socket.readyState );
var arr = [ "a" , "b" , "c" , "d" ];
socket.send( arr );
alert( "訊息已傳送..." );
};
伺服端可以使用Encoding.UTF8.GetString方法,將收到的位元組陣列轉換字串。以此範例而言,伺服端收到的資料轉換成字串的結果為:「a,b,c,d」,陣列中的元素將會以逗號作區隔;因此只需要利用string類別的split方法,根據「,」號將字串切割之後,就可以利用索引取出任一個陣列元素值:
<%@ 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 [ 1024 ] );
WebSocketReceiveResult r = await socket.ReceiveAsync( buffer , CancellationToken.None );
if ( socket.State == WebSocketState.Open )
{
string msg = Encoding.UTF8.GetString( buffer.Array );
string [ ] data = msg.Split( new char [ ] { ',' } );
msg = "伺服端收到你傳送的訊息 : 第一個文字是 : " + data [ 0 ];
buffer = new ArraySegment<byte>( Encoding.UTF8.GetBytes( msg ) );
await socket.SendAsync( buffer , WebSocketMessageType.Text , true , CancellationToken.None );
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
此網頁範例執行的結果,請參考下圖所示:

圖 4:傳送字串陣列範例。
傳送文字檔案範例
用戶端也可以將檔案傳送到伺服端,只要在網頁中使用型別為file的input項目,瀏覽器就可以顯示選取檔案的方塊,讓你挑選要傳送到Websocket的檔案,參考以下範例:
<!DOCTYPE html>
<html xmlns = "
http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv = "Content-Type" content = "text/html; charset=utf-8" />
<title> </title>
<script type = "text/javascript" >
function openSocket( ) {
var socket = new WebSocket( "ws://localhost:26462/WSHandler2.ashx" );
socket.onopen = function ( ) {
alert( "建立與伺服端的連線! state :" + socket.readyState );
var file = document.querySelector( 'input[type="file"]' ).files[0];
socket.send( file );
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 );
};
}
</script>
</head>
<body>
<input id = "Button1" type = "button" value = "Connect to Server" onclick = "openSocket()" />
<input id = "File1" type = "file" />
</body>
</html>
伺服端收到檔案之後,便可從buffer.Array取出檔案內容,並利用FileStream物件將檔案儲存在伺服端:
<%@ 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 [ 1024 ] );
WebSocketReceiveResult r = await socket.ReceiveAsync( buffer , CancellationToken.None );
if ( socket.State == WebSocketState.Open )
{
int len = buffer.Array.Length;
System.IO.FileStream s = new System.IO.FileStream( HttpContext.Current.Server.MapPath( "data.txt" ) , System.IO.FileMode.Create , System.IO.FileAccess.ReadWrite );
s.Write( buffer.Array , 0 , len );
s.Close( );
string msg = len.ToString( );
msg = "伺服端收到你傳送的訊息 : " + msg + " 時間 : " + DateTime.Now.ToString( );
buffer = new ArraySegment<byte>( Encoding.UTF8.GetBytes( msg ) );
await socket.SendAsync( buffer , WebSocketMessageType.Text , true , CancellationToken.None );
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
此網頁範例執行的結果,請參考下圖所示,先選取要傳送的文字檔,再傳送到伺服器:

圖 5:傳送文字檔案範例。
伺服器回傳的訊息,請參考下圖所示:

圖 6:傳送文字檔案範例。
整合拖曳功能傳送檔案
在實務上,我們經常使用拖曳的方式,將檔案傳送到伺服端,你可以整合HTML5拖曳功能來傳送檔案。關於HTML5拖曳功能在本站《.NET Magazine國際中文電子雜誌》的《使用HTML 5 File API(1)》一文中已有詳細的說明,本文不再贅述,參考以下範例延續上一個範例情境,但改用拖曳的方式進行檔案上傳:
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv ="Content-Type" content = "text/html; charset=utf-8" />
<title> </title>
<script type = "text/javascript" >
function wireDragEvents( ) {
var div = document.getElementById( 'dropDiv' );
div.addEventListener( 'drop' , handleDrop , false );
div.addEventListener( 'dragenter' , handleEnter , false );
div.addEventListener( 'dragover' , handleDragOver , false );
}
function handleEnter( e ) {
document.getElementById( 'dropDiv' ).textContent = "";
e.stopPropagation( );
e.preventDefault( );
}
function handleDrop( e ) {
e.stopPropagation ();
e.preventDefault( );
var files = e.dataTransfer.files;
var file = files[0];
document.getElementById( 'dropDiv' ).innerHTML += " <br/>" +
" 檔案名稱 :" + file.name + " <br/> " +
" 檔案大小 : " + file.size + "<br/> " +
" 最後修改時間 : " + file.lastModifiedDate;
var socket = new WebSocket( "ws://localhost:26462/WSHandler2.ashx" );
socket.onopen = function ( ) {
socket.send( file );
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 );
};
}
function handleDragOver( e ) {
e.stopPropagation( );
e.preventDefault( );
e.dataTransfer.dropEffect = 'copy';
}
window.addEventListener( "DOMContentLoaded", wireDragEvents, false );
</script>
</head>
<body>
<div id = "dropDiv" dropzone = "copy" style = "width: 300px; height: 200px; padding: 50px; border: solid 2px black;" >
請拖曳檔案到此區塊以上傳到伺服器
</div>
</body>
</html>
此網頁範例執行的結果,請參考下圖所示,執行時顯示可以拖放檔案的區塊:

圖 7:整合拖曳功能傳送檔案。
從檔案總管拖曳檔案到網頁中的區塊之後,執行結果如下所示:

圖 8:整合拖曳功能傳送檔案。
傳送JSON格式資料範例
用戶端若要傳送JSON格式資料,只需要建立物件,設好屬性之後,利用JSON.stringify方法,將物件序列化成字串後,便可以進行傳送,例如以下範例所示:
<!DOCTYPE html>
<html xmlns = http://www.w3.org/1999/xhtml >
<head>
<meta http-equiv = "Content-Type" content = "text/html; charset=utf-8" />
<title> </title>
<script type = "text/javascript" >
function openSocket( ) {
var socket = new WebSocket( "ws://localhost:26462/WSHandler3.ashx" );
socket.onopen = function ( ) {
alert( "建立與伺服端的連線! state :" + socket.readyState );
var emp = {
ID : document.getElementById("Text1").value,
Name : document.getElementById("Text2").value,
Age : document.getElementById("Text3").value
};
var s = JSON.stringify( emp );
socket.send( s );
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 );
};
}
</script>
</head>
<body>
<fieldset>
<legend>Personal Data</legend>
<label for = "Text1"> ID: </label>
<input id = "Text1" type = "text" /> <br />
<label for = "Text2"> Name: </label>
<input id = "Text2" type = "text" /> <br />
<label for = "Text3"> Age: </label>
<input id = "Text3" type = "text" /> <br />
</fieldset>
<input id = "Button1" type = "button" value = "Connect to Server" onclick = "openSocket()" />
</body>
</html>
伺服端收到字串格式的JSON格式資料之後,可以利用JavaScriptSerializer物件進行還原序列化成IDictionary<string , object>字典類型物件,參考以下範例所示:
<%@ 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 [ 1024 ] );
WebSocketReceiveResult r = await socket.ReceiveAsync( buffer , CancellationToken.None );
if ( socket.State == WebSocketState.Open )
{
var json = Encoding.UTF8.GetString( buffer.Array , 0 , r.Count );
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer( );
var emp = ( System.Collections.Generic.IDictionary<string , object> ) serializer.DeserializeObject( json );
var ID = emp [ "ID" ];
var Name = emp [ "Name" ];
var Age = emp [ "Age" ];
string msg = ID + "," + Name + "," + Age;
msg = "伺服端收到你傳送的訊息 : " + msg + " 時間 : " + DateTime.Now.ToString( );
buffer = new ArraySegment<byte>( Encoding.UTF8.GetBytes( msg ) );
await socket.SendAsync( buffer , WebSocketMessageType.Text , true , CancellationToken.None );
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}

圖 9:傳送JSON格式資料範例。

圖 10:傳送JSON格式資料範例,用戶端接收到的訊息。
接收伺服端JSON格式資料範例
若用戶端預期將收到伺服端回傳的JSON格式資料,便可以在message事件中,利用JSON.parse方法將取回的字串還原成物件,便可直接存取物件的屬性值,例如以下範例程式:
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv = "Content-Type" content = "text/html; charset=utf-8" />
<title ></title>
<script type = "text/javascript">
function openSocket( ) {
var socket = new WebSocket( "ws://localhost:26462/WSHandler4.ashx" );
socket.onopen = function ( ) {
var emp = {
ID : document.getElementById("Text1").value,
Name : document.getElementById("Text2").value,
Age : document.getElementById("Text3").value
};
var s = JSON.stringify( emp );
socket.send( s );
alert( "訊息已傳送..." );
};
socket.onmessage = function ( event ) {
var msg = event.data;
var emp = JSON.parse( msg );
document.getElementById( "result" ).innerHTML = "已收到伺服器傳送的訊息 : "
+ emp.ID + "," + emp.Name + "," + emp.Age;
};
socket.onclose = function ( event ) {
alert( "連線已關閉... state :" + socket.readyState );
};
socket.onerror = function ( event ) {
alert( "發生錯誤 : " + event.data );
};
}
</script>
</head>
<body>
<fieldset>
<legend>Personal Data</legend>
<label for = "Text1"> ID:</label>
<input id = "Text1" type = "text" /> <br />
<label for = "Text2"> Name:</label>
<input id = "Text2" type = "text" /> <br />
<label for = "Text3"> Age:</label>
<input id = "Text3" type ="text" /> <br />
</fieldset>
<input id = "Button1" type = "button" value = "Connect to Server" onclick = "openSocket()" />
<div id = "result"></div>
</body>
</html>
伺服端若要送出JSON格式的資料,可以利用JavaScriptSerializer類別的Serialize方法,將物件序列化成JSON格式的資料來傳送,參考以下範例程式碼:
<%@ 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 [ 1024 ] );
WebSocketReceiveResult r = await socket.ReceiveAsync( buffer , CancellationToken.None );
if ( socket.State == WebSocketState.Open )
{
var json = Encoding.UTF8.GetString( buffer.Array , 0 , r.Count );
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer( );
var emp = ( System.Collections.Generic.IDictionary<string , object> ) serializer.DeserializeObject( json );
var obj = new
{
ID = emp [ "ID" ] ,
Name = emp [ "Name" ] ,
Age = emp [ "Age" ]
};
serializer = new System.Web.Script.Serialization.JavaScriptSerializer( );
var msg = serializer.Serialize( obj );
buffer = new ArraySegment<byte>( Encoding.UTF8.GetBytes( msg ) );
await socket.SendAsync( buffer , WebSocketMessageType.Text , true , CancellationToken.None );
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
此網頁範例執行的結果,請參考下圖所示:

圖 11:接收伺服端JSON格式資料範例。
傳送Canvas資料範例
用戶端若使用HTML5 的Canvas進行繪圖,若想要將繪製的結果上傳到伺服器,參考以下的範例將WebSocket物件的binaryType設定為「arraybuffer」,表示以ArrayBuffer來表示繪圖資料,binaryType的預設值是「blob」。接著利用getImageData,從(0,0),取出寬、高為10的繪圖資料,放到Uint8Array陣列之中,以便傳送到伺服器。在message事件中,則利用Canvas的putImageData方法,將伺服端傳回的資料繪製在下方的Canvas之中:
<!DOCTYPE html>
<html xmlns= "http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv = "Content-Type" content = "text/html; charset=utf-8" />
<title> </title>
<script type = "text/javascript">
function openSocket( ) {
var socket = new WebSocket( "ws://localhost:26462/WSHandler6.ashx" );
socket.binaryType = 'arraybuffer';
socket.onopen = function () {
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var image = context.getImageData( 0, 0, 10, 10 );
var binArray = new Uint8Array( image.data.length );
for ( var i = 0; i < image.data.length; i++ ) {
binArray[i] = image.data[i];
}
socket.send( binArray );
};
socket.onmessage = function ( event ) {
var data = event.data;
var binArray = new Uint8Array( data );
var canvas = document.getElementById( "serverCanvas" ).getContext("2d");
var image = canvas.createImageData( 10, 10 );
for ( var i = 0; i < image.data.length; i++ ) {
image.data[i] = binArray[i];
}
canvas.putImageData( image, 0, 0 );
};
socket.onclose = function ( event ) {
alert( "連線已關閉... state :" + socket.readyState );
};
socket.onerror = function ( event ) {
alert( "發生錯誤 : " + event.data );
};
}
</script>
</head>
<body>
<input id = "Button1" type = "button" value = "Connect to Server" onclick = "openSocket()" />
<br />
<canvas id = "myCanvas" style = "border: 1px solid" >
<div>此瀏覽器不支援 canvas </div>
</canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.fillStyle = "red";
context.fillRect(0, 0, 10, 10);
context.strokeStyle = "blue";
context.arc(0, 0, 10, 10, 0.5 * Math.PI , true);
context.stroke();
</script>
<canvas id = "serverCanvas" style = "border: 1px solid" >
<div>此瀏覽器不支援 canvas </div>
</canvas>
</body>
</html>
伺服端接收到繪圖資料之後,將資料直接送回用戶端:
<%@ 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;
}
public async Task MyWebSocketHandler( AspNetWebSocketContext context )
{
WebSocket socket = context.WebSocket;
while ( true )
{
ArraySegment<byte> buffer = new ArraySegment<byte>( new byte [ 1024 ] );
WebSocketReceiveResult r = await socket.ReceiveAsync( buffer , CancellationToken.None );
if ( socket.State == WebSocketState.Open )
{
await socket.SendAsync( buffer , WebSocketMessageType.Binary , true , CancellationToken.None );
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
注意,本文範例只處理小於1024位元組資料,若資料過多,您可以撰寫一個迴圈,從WebSocketReceiveResult的EndOfMessage屬性判斷是否還有其它資料需要接收,若EndOfMessage屬性為false,代表尚有資料,則可再叫用ReceiveAsync方法,接收後續的資料。此網頁範例執行的結果,請參考下圖所示:

圖 12:傳送Canvas繪圖資料範例。