前回の
記事で 、通常のソケットの上にこのプロトコルを独自に実装したサーバーの例を使用して、WebSocketの操作について既に説明しました。
CachéDBMS 2013.1では、CSPゲートウェイに、WebサーバーとHTML 5互換ブラウザ間のWebSocket接続用のHTML 5仕様のサポートが含まれるようになりました。 この機能は、Apache 2.2以降、およびWindows Server 2012の一部であるIIS 8.0で使用できます。
Apache 2.4は既にCaché2013.1に組み込まれているため、サンプルを実行します。
クライアント部分を実装するために、 
ZENフレームワークが使用されましたが、 
CSPテクノロジーまたはその他を使用して例を再作成できます。
それでは始めましょう。
理論
前述のとおり、CachéDBMSのサーバー側でWebSocketをサポートするためのすべての内部ロジックが引き継がれます。 プログラマは、 
%CSP.WebSocketクラスから継承して独自のクラスを作成し、そのクラスのいくつかのメソッドをオーバーライドするだけです。
クラス
%CSP.WebSocketのオブジェクトは、WebSocketプロトコルを使用したクライアントとサーバー間の通信のイベントハンドラーとして機能します。 すべてのWebSocketサーバーは
%CSP.WebSocketを継承します。
%CSP.WebSocketクラスのメソッドとプロパティの詳細な説明は、クラスリファレンスにあります。
ここでは、そのうちのいくつかだけを簡単に説明します。
| メソッド/プロパティ | 説明 | 
|---|
| 読む() | クライアントからデータを受信する | 
| 書き込み() | クライアントにデータを送信する | 
| OnPreServer() | PreServerイベントハンドラー:WebSocketサーバーを起動する前に呼び出されます | 
| OnPostServer() | PostServerイベントハンドラー:WebSocketサーバーが停止すると呼び出されます | 
| サーバー() | WebSocketサーバー自体 | 
| EndServer() | Websocketサーバーを停止します | 
| 出席する | 読み取り中にWebSocketサーバーが現在のデータフレームの最後に到達すると、プロパティの値はtrue(1)になります | 
| 共有接続 | このプロパティは、クライアントとWebSocketサーバー間の情報交換が専用のCSPゲートウェイ接続を介して行われるか、共有接続のプール(まだ使用されていない)を介して行われるかを決定します | 
練習する
これらすべてを実際に使用する方法の簡単な例を見てみましょう。
まず、 
USER StudioでZENページ( 
demo.WebSocketクラス)を作成し、 
%CSP.WebSocketクラスから継承します。
クラスdemo.WebSocket Extends ( %ZEN.Component.page 、 %CSP.WebSocket ) 
{ 
XData コンテンツ[ XMLNamespace = " www.intersystems.com/zen" ] 
{ 
< page xmlns = " www.intersystems.com/zen" title = "" > 
</ ページ > 
} 
}
JSONの操作をサポートするため
に、zenCSLM.jsファイル
を含めます。
パラメーター JSINCLUDES = "zenCSLM.js" ;
WebSocketを介してクライアントを接続し、対応するイベントを処理するためのメソッドを実装します。
///このクライアントイベントが存在する場合、ページがロードされると発生します。 
ClientMethod onloadHandler()[ 言語 = javascript] 
{ 
ws = null; 
url = ((window.location.protocol == 'https:' ) ? 'wss:' : 'ws:' ) + '//' + window.location.host + window.location.pathname; 
wsCtor = window [ 'MozWebSocket' ] ? MozWebSocket : window [ 'WebSocket' ] ? WebSocket : null; 
if (zenIsMissing(wsCtor))zenAlert( 'WebSocketはブラウザでサポートされていません!' ); 
}
ClientMethod start()[ 言語 = javascript] 
{ 
if ( ! zenIsMissing(wsCtor)){ 
if (zenIsMissing(ws)){ 
ws = 新しい wsCtor(url); 
ws.onopen = function (){ 
zenAlert( 'onopen \ n \ nreadyState:' 、ws.readyState、 '\ nbinaryType:' 、ws.binaryType、 '\ nbufferedAmount:' 、ws.bufferedAmount); 
}; 
ws.onmessage = function (e){ 
zenAlert(e.data); 
}; 
ws.onclose = function (e){ 
zenAlert( 'onclose \ n \ nwasClean:' 、e.wasClean、 '\ ncode:' 、e.code、 '\ nreason:' 、e.reason); 
ws = null; 
}; 
ws.onerror = function (e){ 
zenAlert( 'onerror' ); 
}; 
} 
} 
}
WebSocketサーバーの実装は同じページにあるため、接続文字列はプロトコルを除いて同一になります。 つまり、ZENページのURLの形式が
localhost:57772/csp/user/demo.WebSocket.cls、次にWebSocketサーバーの場合は
ws://localhost:57772/csp/user/demo.WebSocket.cls次に、ページに小さなインターフェイスを追加しましょう。サーバーにデータを接続、切断、送信するためのボタンがいくつかあります。
XData コンテンツ[ XMLNamespace = " www.intersystems.com/zen" ] 
{ 
< page xmlns = " www.intersystems.com/zen" title = "" > 
< text id = "txt" label = "送信するテキスト" value = "World" /> 
< button caption = " 1.Connect " onclick = "zenPage.start();" /> 
< button caption = "2.テキストを送信" onclick = "if(!zenIsMissing(ws))ws.send(zenGetProp( 'txt'、 'value'));" /> 
< button caption = "3.長い行を送信する" onclick = "zenPage.sendLongStr(100000);" /> 
< button caption = "4.Send JSON" onclick = "zenPage.sendJSON();" /> 
< button caption = "5.電源を切る" onclick = "if(!zenIsMissing(ws))ws.close();" /> 
</ ページ > 
}
sendLongStrメソッドの
コードは次のとおりです。
ClientMethod sendLongStr( N )[ 言語 = javascript] 
{ 
if (zenIsMissing(ws)) return ; 
var s = 'a' ; 
for ( var i = 1 ; i < N; i ++ )s + = 'a' ; 
ws.send(s); 
}
sendJSONメソッド
コード :
ClientMethod sendJSON()[ 言語 = javascript] 
{ 
if (zenIsMissing(ws)) return ; 
var obj = { 
"firstName" : "Ivan" 、 
"lastName" : "Ivanov" 、 
「アドレス」 :{ 
"streetAddress" : "モスクワハイウェイ101、 apt。101" 、 
「都市」 : 「レニングラード」 、 
「 郵便番号 」 : 101101 
}、 
「phoneNumbers」 :[ 
「812 123-1234」 、 
「916 123-4567」 
] 
}; 
ws.send(ZLM.jsonStringify(obj)); 
}
WebSocketサーバー自体を実装するときが来ました。 これを行うには、次のように
OnPreServer 、 
OnPostServer、および
Serverメソッドをオーバーライドします。
メソッド OnPreServer() As%Status 
{ 
$ system .Processを実行し ます。 未定義 (2) 
Set ^ tmp( $ Increment (^ tmp)、 "OnPreServer" )= "" 
$$$ OKを終了OK 
}
メソッド OnPostServer() As%Status 
{ 
Set ^ tmp( $ Increment (^ tmp)、 "OnPostServer" )= "" 
$$$ OKを終了OK 
}
メソッド サーバー() As%ステータス 
{ 
{ 
len = 32656に 設定 
設定 データ = $ ZConvert (.. 読み取り ( 。Len , . Status )、 "I" 、 "UTF8" ) 
$$$ ISOK ( status ) { 
data = "World"の 場合 { 
。。Write ( $ ZConvert ( "Hello、" _ data _ "!" 、 "O" 、 "UTF8" )) 
} ElseIf data = "bye" { 
; WebSocketサーバーを強制的にシャットダウンし、無限ループを終了します 
; oncloseはクライアントで動作します 
Do .. EndServer () 
やめる 
} その他 { 
#Dim obj As %RegisteredObject = $$$ NULLOREF 
Set ^ tmp = $ Increment (^ tmp) 
; 文字列をオブジェクトに変換する 
$$$ ISOK ( ##クラス ( %ZEN.Auxiliary.jsonProvider )。 %ConvertJSONToObject ( data ,,。 Obj )) { 
; エラーがない場合、プロパティ値を保存します 
^ tmp(^ tmp、 "Server" 、 "firstName" )= objを設定し ます。 firstName 
^ tmp(^ tmp、 "Server" 、 "lastName" )= objを設定し ます。 lastName 
^ tmp(^ tmp、 "Server" 、 "address.streetAddress" )= objを設定し ます。 住所 streetAddress 
^ tmp(^ tmp、 "Server" 、 "address.city" )= objを設定し ます。 住所 市 
^ tmp(^ tmp、 "Server" 、 "address.postalCode" )= objを設定し ます。 住所 postalCode 
^ tmp(^ tmp、 "Server" 、 "phoneNumbers.1" )= objを設定し ます。 phoneNumbers 。 GetAt (1) 
^ tmp(^ tmp、 "Server" 、 "phoneNumbers.2" )= objを設定し ます。 phoneNumbers 。 GetAt (2) 
; 姓を変更 
objを 設定し ます。 lastName = "Sidorov" 
; 別の電話を追加 
objを実行し ます。 phoneNumbers 。 挿入 ( "111 111-1111" ) 
; オブジェクトにさらに2つの新しいプロパティを追加します。 
objを 設定し ます。 name = "Vasya" 
objを 設定し ます。 street = "17 Mira Street" 
; 変更されたオブジェクトを文字列に変換し、クライアントに送り返します 
Do .. Write (.. Write2Str ( 。Obj )) 
} その他 { 
; 長い文字列を受信したときにデータを保存する 
Set ^ tmp(^ tmp、 "Server" 、 "longStr" )= .. AtEnd _ ":" _ $ Length ( data )_ ":" _ len 
} 
} 
} その他 { 
終了 :( $$$ GETERRORCODE ( status )= $$$ CSPWebSocketClosed ) 
} 
} 
$$$ OKを終了OK 
}
Write2Strユーティリティメソッドは、Writeコマンドによって出力されたデータを文字列にアセンブルするために使用されます。
ClassMethod Write2Str( ByRef obj ) As%String [ プライベート ] 
{ 
{ 
tIO = $ IO 、 tXDEV = "| XDEV |"を設定します _ + $ Job 
{ 
// $$$ IsUnicodeにはUTF-8を使用します 
オープン tXDEV :( $ ZF (-6、 $$$ XSLTLibrary 、12): "" : "S" :/ HOSTNAME = "XSLT" :/ IOT = $ Select ( $$$ IsUnicode : "UTF8" 、1: " RAW " ):/ IBU = 16384:/ OBU = 16384) 
tXDEVを 使用する 
終了 : $$$ ISERR ( obj 。 %ToJSON (、 "aeloiwu" )) 
//残りの出力をフラッシュします 
書き込み * -3 
//ここで文字列を読み戻します(最大長まで、32kまたは長い文字列の場合は約4MB) 
s = ""を 設定 
while (1) { 
#Dim tChunk As %String 
tChunk を読み取り ます :0 
終了 : ' $長さ ( tChunk ) 
s = s _ tChunkを 設定 
} 
} while (0) 
} キャッチ {} 
tXDEVを 閉じ ます 
tIOを 使用する 
終了 
}
クラスをコンパイルし(Ctrl + F7)、ブラウザーで表示するために開いたままにします(F5)。
ボタンを連続して押すと、^ tmpグローバルの内容は次のようになります。
^tmp=7^tmp(1,"OnPreServer")=""^tmp(2,"Server","longStr")="0:32656:32656"^tmp(3,"Server","longStr")="0:32656:32656"^tmp(4,"Server","longStr")="0:32656:32656"^tmp(5,"Server","longStr")="1:2032:2032"^tmp(6,"Server","address.city")=""^tmp(6,"Server","address.postalCode")=101101^tmp(6,"Server","address.streetAddress")=" ., 101, .101"^tmp(6,"Server","firstName")=""^tmp(6,"Server","lastName")=""^tmp(6,"Server","phoneNumbers.1")="812 123-1234"^tmp(6,"Server","phoneNumbers.2")="916 123-4567"^tmp(7,"OnPostServer")=""demo.WebSocketクラスの
ソースコードをダウンロードし
ます 。