記事
· 2 hr 前 5m read

WebSocketの使用

これは InterSystems FAQ サイトの記事です。
 

WebSocketは、リアルタイム双方向通信を可能にするプロトコルで、Webアプリケーションの動的な操作性を向上させるために広く活用されています。

この技術は、TCP上で動作し、HTTPプロトコルを介して接続を確立します。

一度接続が確立されると、持続的な接続が維持され、サーバーとクライアントが効率的にデータを交換できるのが特徴です。

通常のHTTP通信の場合、クライアントからのリクエストに対してサーバーが応答するというのが基本的な動作になるため、サーバーから非同期にデータを送信することが難しいですが、WebSocketを利用することでそのような機能を簡単に実現できます。

一方で、サーバーからの一方向の非同期通信が実現できれば良いという要件であれば、SSE (Server-Sent Events)を使用することもできます。

一般的にWebSocket通信が最も適していると考えられるのは、クライアント・サーバー間で双方向にデータを交換する必要がある場合になります。

双方向の接続を維持する必要があるため、状況によって、サーバー上のコンピュータ資源の消費(メモリー、CPU、IRISライセンス使用量など)に注意する必要があります。

ネット上にもWebSocketに関する様々な情報(メリット・デメリットを含む)がありますので、インターネット上での検索や生成AIに確認してみてください。

ここではIRISでWebSocketを利用する方法について、説明します。

IRISでWebSocketを実現するためには、%CSP.WebSocketクラスを継承したクラスを作成し、必要なインタフェース(メソッド)を実装する必要があります。

以下のように、OnPreServerとServerインスタンスメソッドを実装します。

OnPreServerメソッドは、WebSocketの接続の際に最初に呼ばれるメソッドで、接続の前に実行する必要のあるコードを記述します。

SharedConnectionプロパティの設定を、このメソッドで実行することが一般的です。

Serverメソッドはクライアントからのリクエストに応答するための処理を記述します。

その処理概要は、以下のような流れです。

  • クライアントからのリクエストに応答するためにReadメソッドをこのメソッドの中で呼び出します。
  • クライアントからの応答があると、このReadメソッドはその応答内容を取得します。
  • その応答の内容に基づき、適切な処理を実行し、その結果をWriteメソッドで返します。
  • この一連の処理(ReadメソッドとWriteメソッド)を繰り返します。
  • 繰り返し処理を終了する条件は、クライアントからの終了を指示するメッセージを取得した場合や以下のコード例のようにReadメソッドにて指定したタイムアウト値を超えて、クライアントからの応答を得られなかった場合などを設定できます。
  • そして最後にEndServerメソッドを呼び出してWebSocketの接続を切断します。
Class User.WebSocket Extends %CSP.WebSocket
{

Method OnPreServer() As %Status
{

    set ..SharedConnection = +$get(^websocket("smode"))

    quit $$$OK
}

Method Server() As %Status [ ProcedureBlock = 0 ]
{
    try {
      set cnt=$I(^websocket)

      set ^websocket(cnt,"wid") = ..WebSocketID
      set ^websocket(cnt,"sid") = ..SessionId
      set ^websocket(cnt,1)="start: job # = "_$job_" datetime = "_$ZDT($H)

      set sc=$$$OK
      set scount = 0
      for {

        // クライアントからのメッセージを読み取る
        set data = ..Read(0,.sc,200) // Disconnect if no communication for 200 sec
        if $$$ISERR(sc) {
          // read timeout or the client requets close()	
          set ^websocket("error",$zh) = $system.Status.GetErrorText(sc)
          quit
        }
 
        set ^websocket(cnt,$increment(scount))=data

        ;; メッセージをクライアントに送信
        do ..Write("XYZ")

        //quit  // Disconnect
      }

      do ..EndServer()

      set ^websocket(cnt,2)="close: "_$ZDT($H)

  }
  catch e {
    set status = e.AsStatus()
    set ^websocket("error",$zh) = $system.Status.GetErrorText(status)
  }
  quit $$$OK
}

 

クライアント側のコードのサンプルは以下のようになります。

<html>
<head>
<title>WebSocket test</title>
<script language="JavaScript">

var ws=null;

function createSocket() {

  ws=new WebSocket('ws://localhost:8080/csp/user/User.WebSocket.cls');

  ws.binaryType='blob';

  ws.onopen=function(event)   { alert('socket created!');      };

  ws.onmessage = function(event) { alert('receive data ' + event.data); };

  ws.onerror = function(event)  { alert('connection error');      };

  ws.onclose = function(event)  { ws=null; alert('closed');      };

}

function sendMsg() {

 var json=JSON.stringify( {message:123} );

 try{

   var blob = new Blob([json], {type : 'application/json'});

   ws.send(blob);

 }

 catch (e) {

   alert('send error\n' + e);

 }

}

</script>
</head>
<body>
<form>
<input type="button" name="xxx" value="create socket" onClick="createSocket();"><hr>
<input type="button" name="btn" value="hello" onClick="sendMsg();"><hr>
<input type="button" name="close" value="close socket" onClick="ws.close();">
</form>
</body>
</html>

SharedConnectionプロパティの値の設定により、接続の形態を制御できます。

この値がゼロ(デフォルト値)の場合、接続は、同期モードとなり、サーバーとクライアントは一対一のプライベートな関係になります。

この値を1に設定すると、接続は、非同期モードとなり、サーバーから複数クライアントに対して、同報メッセージ送信のような機能を実現することができます。

以下に同報通信を実行するコードサンプルを示します。

ClassMethod SendDataAsync() As %Status
{
    try {

      set count = $get(^websocket)
      for i = 1:1:count {
        set websocket = ##class(%CSP.WebSocket).%New()
        set websocketid = $get(^websocket(i,"wid"))
        set status = websocket.OpenServer(websocketid)
		$$$ThrowOnError(status)
        set status = websocket.Write("How are you?")
		$$$ThrowOnError(status)
      }
    }
    catch e {
      set status = e.AsStatus()
      set ^websocket("error",$zh) = $system.Status.GetErrorText(status)
    }
	quit $$$OK
}

ここで示したサンプルは、以下からも取得できます。

WebSocketのサンプル

IRISのWebSocketに関連する機能の詳細は、以下のドキュメントを確認してください。

WebSocketの使用

IISをWebサーバーとして利用する際には、IISにWebSocket機能のインストール作業が必要です。

その作業については、インターネット上で検索するか、生成AIにご確認ください。

ディスカッション (0)1
続けるにはログインするか新規登録を行ってください