相互接続が増しつつある世界においては、Webサイトや IoTアプリケーションがリアルタイムで更新されることが重要です。
相手に瞬時に情報を配信する方法として、サーバーとクライアントの間に双方向通信のチャンネルを提供する WebSocketプロトコルを使用することができます。v20 より、4D は WebSocketサーバーを作成するためのコマンドを提供します。
WebSocketサーバーを管理するために、4D は 2つの新しいビルトインクラスを提供します:
- 最初の 4D.WebSocketServer は、サーバー自体を管理するクラスです
- 2つ目の 4D.WebSocketConnection は、WebSocket接続を管理するクラスです
この機能を確認するために、簡単なチャットサーバーを作成してみましょう!
WebSocketサーバークラスを使用する前に、まずは 4D の Webサーバーを起動します。
4D.WebSocketServer
このクラスを使って、サーバーで発生するイベントを管理します。そのために、以下のような関数を持つユーザークラスを作成する必要があります:
- onConnection(): 新しい接続がリクエストされたときに呼び出されます。
- onOpen(): サーバー起動時に呼び出されます。
- onTerminate(): サーバー終了時に呼び出されます。
- onError(): エラー発生時に呼び出されます。
ここでは、WSServerHandlerクラスという名前のユーザークラスを作成します。
チャットの例では、最初に接続リクエストを管理する必要があります。onConnection() 関数は、Null を戻り値として返せば接続をキャンセルします。接続を許可する場合は、その後のメッセージの送受信を管理するためのオブジェクトを返します。サンプルでは、WSConnectionHandlerクラス (次のセクションで説明します) を返しています:
Class constructor
Function onConnection($wss : Object; $param : Object) : Object
// VerifyAddress メソッドを呼び出して、リモートアドレスからの接続を許可するか判断します
If (VerifyAddress($param.request.remoteAddress))
// 接続を許可する場合
// WSConnectionHandler オブジェクトが返されます
// 4D はこのオブジェクトを使って、この接続に紐づけられた
// 4D.WebSocketConnection オブジェクトをインスタンス化します
return cs.WSConnectionHandler.new()
Else
// 接続がキャンセルされます
return Null
End if
WebSocketサーバーの開始と終了、そしてエラーのログを取りたいので、WSServerHandlerクラスに下の通り追加します:
Function onOpen($wss : Object; $param : Object)
LogFile("*** Server started")
Function onTerminate($wss : Object; $param : Object)
LogFile("*** Server closed")
Function onError($wss : Object; $param : Object)
LogFile("!!! Server error: "+$param.statusText)
4D.WebSocketConnection
このクラスを使って、特定の接続に関わるイベントを管理します。以下のような関数を持つユーザークラスを作成する必要があります:
- onMessage(): この接続を介したメッセージを受信するたびに呼び出されます。
- onOpen(): 4D.WebSocketConnection オブジェクトが作成されるときに呼び出されます。
- onTerminate(): 4D.WebSocketConnection オブジェクトが終了されたときに呼び出されます。
- onError(): エラー発生時に呼び出されます。
チャットの例では、WSConnectionHandlerクラスという名前のユーザークラスを作成します。
- 接続時に、新しいユーザーが接続されたことを他のユーザーに知らせます。
- 接続終了時に、ユーザーが切断されたことを他のユーザーに知らせます。
- メッセージを受信すると、接続中の他のチャットクライアントにメッセージをブロードキャストします。
Function onMessage($ws : 4D.WebSocketConnection; $message : Object)
// 他のチャットクライアントにメッセージをブロードキャストします
This.broadcast($ws;$message.data)
Function onOpen($ws : 4D.WebSocketConnection; $message : Object)
// 接続したユーザーにメッセージを送信します
$ws.send("チャットへようこそ!")
// 他のクライアントへは "新しいクライアントが接続しました" というメッセージを送信します
This.broadcast($ws;"新しいクライアントが接続しました")
Function onTerminate($ws : 4D.WebSocketConnection; $message : Object)
// "クライアントが切断されました" メッセージを他のクライアントに送信します
This.broadcast($ws;"クライアントが切断されました")
Function broadcast($ws : 4D.WebSocketConnection; $message : Text)
var $client:4D.WebSocketConnection
// 他のチャットクライアントにメッセージをブロードキャストします
For each ($client; $ws.wss.connections)
// クライアントの id が発信者と同一でない場合にメッセージを送信します
If ($client.id#$ws.id)
$client.send($message)
End if
End for each
あとは、上記で作成したクラスを使ってウェブソケットサーバーを起動するだけです。ウェブソケットサーバーはワーカーで起動する必要があるので、CALL WORKERコマンドで新しいプロセスを作成し、その中で4D.WebSocketServerをインスタンス化します:
var $handler:cs.WSSHandler
$handler:=cs.WSServerHandler.new()
CALL WORKER("WebSocketServer"; Formula(WSS:=4D.WebSocketServer.new($handler)))
//WebSocketに変数(WSS)を割り当てると、その後にWSS.terminate()を呼び出すことができる。
作成されたウェブソケットサーバは、ワーカーが強制終了されるか .terminate() 関数が呼ばれるまで存在します。
CALL WORKER("WebSocketServer"; Formula(WSS.terminate()))
クライアント側
HTML と Javascript でチャットインターフェースを作成するコードの例です:
このコードは、HTTPポート 80 のローカルWebサーバーで動作するように設計されています (18行目: const urlwss=”ws://127.0.0.1:80/”;)。
上の HDI とドキュメントにて、この機能の詳細を確認してください!