まず、コマンドラインアプリを「WebSocketServer」という名前で作成します。最初に、dart:ioライブラリをインポートしておきましょう。
#import('dart:io');
次に、ホスト名とポート番号をfinal変数で用意しておきます。ここではホスト名をIPアドレスで指定しています。
final HOST = '127.0.0.1'; final PORT = 8000;
最初に「createResponse」という関数を作っておきましょう。引数で渡ってきたdataをJSON形式にして返すだけのものです。
String createResponse(String data) { return '{ "echo": "$data" }'; }
次に、main関数を用意して、その中に処理を追加していきます。
void main() { }
DartでWebSocketを使うには、HttpServerを用意してから、WebSocketHandlerをハンドラとしてaddRequestHandlerメソッドで登録します。このときに、どんなリクエストパスが来たときに応答をするかも指定できます。
ここでは、「(req) => req.path == "/echo.json」として、echo.jsonへアクセスしたときに応答するようにしています。
HttpServer server = new HttpServer(); WebSocketHandler wsHandler = new WebSocketHandler(); server.addRequestHandler((req) => req.path == "/echo.json", wsHandler.onRequest);
クライアントから接続が来ると、ハンドラ(ここではwsHandler)のonOpenメソッドが呼び出されます。呼び出されたら「accept」とコンソールへ出力しています。コネクションに対応するのはWebSocketConnection型のconnになるので、同時にこの変数についてonMessageメソッドとonCloseメソッドと、onErrorメソッドを登録します。
「conn.onMessage=関数」といった形になっていることに注意をしてください。例えば「conn.onError」の右辺は「(e) { print('Error:$e'); }」となっていて、引数eを持ち、処理が「print('Error:$e');」という関数になっています。
wsHandler.onOpen = (WebSocketConnection conn) { print('accept'); conn.onMessage = (data) { print("$data"); String s = createResponse(data); print("$s"); conn.send("${s}"); }; conn.onClosed = (int status, String reason) { print('$status:$reason'); }; conn.onError = (e) { print('Error:$e'); }; };
onMessageメソッドでは、データがクライアントから渡ってくるので、これを受け取って、print関数でコンソールへ出力しています。また、先に作っておいたcreateResponse関数を呼び出してデータをJSON形式にしています。確認できるようにJSONの値をコンソールへ出力してから、WebSocketConnectionのsendメソッドを使って、クライアントへ結果を送信しています。
onClosedメソッドは接続が終了したときに呼ばれますし、onErororメソッドはエラーが発生したときに呼ばれます。処理の内容は見てのとおり、ここではprint関数を呼び出しているだけです。
最後にサーバを待機状態にします。こうすることで、サーバは接続が来るのを待ち、クライアントが接続したら、ハンドラのonOpenメソッドを呼び出すようになります。
server.listen(HOST, PORT);
次に、Webアプリとして「WebSocketClient」を作成してください。生成された「WebSocketClient.html」のid値がcontainerの<div>要素について、<body>部を次のように修正します。<script>要素はそのまま残してください。
<h1>WebSocketClient</h1> <span id="send" style="background-color:#ccc;">SEND</span><br /> <div id="container"> <input id="text" /> <p id="echo"></p> </div> <script type="application/dart" src="WebSocketClient.dart"></script> <script src="http://dart.googlecode.com/svn/branches/bleeding_edge/dart/client/dart.js"></script>
「WebSocketClient.css」についても必要であれば調整をしてください。#containerと#textの指定を削除して、次のような簡単なものにしました。
body { background-color: #F8F8F8; font-family: 'Open Sans', sans-serif; font-size: 14px; font-weight: normal; line-height: 1.2em; margin: 15px; } p { color: #333; }
クライアントアプリのコードを作成します。生成されたコードはすべて削除してから、まずは、dart:htmlとdart:jsonのライブラリをインポートします。
#import('dart:html'); #import('dart:json');
接続先を示すuriをfinal変数で用意します。ホスト名、ポート番号、リクエストパスはサーバ側で指定したものに合わせてください。
final uri = 'ws://localhost:8000/echo.json';
簡単なクラスとしてvalueというプロパティだけを持つMessageクラスを用意してみました。
class Message { String value; }
キーワード class を使って定義しています。ちなみにDartではプロパティのアクセス制御は「public」か「private」しかありません。privateにするには「_value」のように変数を「_」で始まるように指定します。
次にmain関数を記述します。
void main() { Client client = new Client(); }
今回はClientクラスを用意して、その中に処理を書きました。クラスのインスタンスを生成するのにはnewキーワードを使います。
次にClientクラスを作成します。
class Client { WebSocket webSocket = null; InputElement elemText = null; ParagraphElement elemEcho = null; }
プロパティとしてはWebソケットを表すWebSocket、Inputフィールドを表すInputElement、p要素を表すParagraphElementのデータを持つようにしました。このコードへ、これから説明をするコンストラクタやメソッドを追加していきます。
Clientクラスのコンストラクタは、次のようになります。
Client() { webSocket = new WebSocket(uri); webSocket.on.message.add((MessageEvent e) { receivedData(e.data); }); elemText = query("#text"); elemEcho = query("#echo"); elemText.value = "Welcome to Dart!"; query("#send").on.click.add(sendData); }
WebSocketのインスタンスを生成して、そのインスタンスにメッセージが渡ってきたときに実行する処理としてreceivedDataメソッドを指定しています。query関数はHTMLの要素を取得するために使うもので、"#text"とするとid値が"text"の要素を返します。
<input>要素のvalue属性値を初期化するために、「elemText.value」へ「 "Welcome to Dart!"」を指定しています。最後に、id値が"send"の要素について、クリックされたらsendDataメソッドを呼ぶように「query("#send").on.click.add(sendData);」と指定します。
sendDataメソッドはサーバへデータを送信する処理です。
void sendData(Event event) { if (webSocket == null) { print('not connected'); return; } if (webSocket.readyState == WebSocket.OPEN) { webSocket.send(elemText.value); } else { print('not opend: ${elemText.text}'); } }
webSocketが使える状態になっていないと、データ送信ができないので、nullなら「not connected」というメッセージを表示してメソッドを終了するようにしています。
またreadyStateプロパティの値がWebSocket.OPENでないときも送信はしません。webSocketが使えるときだけ、「webSocket.send(elemText.value);」としてInput要素に入力された値をデータとしてサーバへ送信しています。
receivedData関数はサーバからのデータを受信する処理です。
void receivedData(var data) { var obj = JSON.parse(data); Message msg = new Message(); msg.value = obj['echo']; print(msg.value); String s = JSON.stringify(obj); elemEcho.text = s; }
「JSON」クラスの使い方を示しています。まず、受け取った文字列からJSONオブジェクトを生成しています。生成に当たってはJSONクラスのparseメソッドを使っています。この場合、objはリスト型の値となっているので、「obj['echo']」とすることで、値を取得できます。これをmsg.valueへ代入しています。
JSONクラスには、オブジェクトをJSONの文字列表現へ変換するstringifyメソッドもあります。これを使ってJSON形式にした値をsへ代入しています。最後に「elemEcho.text = s;」としてid値echoのp要素の属性textへsを代入しています。これにより、画面にJSONデータが表示されます。
準備ができたら、WebSocketServer.dartを実行してから、WebSocketClient.dartを実行してみましょう。Dartiumで表示された画面で、「Welcome to Dart!」と入力してから「send」をクリックすると、「{ "echo": "Welcome to Dart!" }」とサーバから値を送り返してくるはずです。
今回のサンプルは、こちらからダウンロードできます。
Dartを使ってみてどうでしたか? クラスベースのオブジェクト指向言語なので、結構理解しやすかったのではないでしょうか。
また、コーディングもしやすかったのではないでしょうか? 変数の型が分からなかったり、決めていなかったりしても、取りあえずvarで宣言しておいて、後で修正できるので、勢いで書けてしまいます。
もちろん、型をしっかりと指定しながら開発を進めることもできます。たまには、こういった言語も使って楽しんでみてはいかがでしょうか?
@IT関連リンク
Javaの常識を変えるPlay framework入門
サーブレット/JSPを基にする重厚長大なJavaのWeb開発のイメージを変える軽量フレームワーク「Play」について解説し、Webアプリの作り方を紹介する入門連載
スケーラブルで関数型でオブジェクト指向なScala入門
Scalaの特徴を紹介し、基本構文や関数、クラスなど、Scalaの基本的な機能について解説する入門連載
実用レベルに達したJRubyを体感してみよう
もはやJava技術者にとって無視できない存在になったRuby。Javaと融合したJRubyの特徴や利点について解説します。実用レベルになったといわれる、その実力を体感してみよう
Groovyに触ってみよう
developerWorks Java言語の厳格さや懐の深さとは対照的に、使いやすさと利便性、小回りの良さを武器にしたJavaプラットフォーム上の新言語が登場した
「Java Solution」フォーラム 2004/9/25
Google App Engineで手軽に試すJavaクラウド
Javaに対応したことでユーザー数が一気に増加する可能性がある無料でお手軽なクラウド環境Google App Engineの超入門連載です。概要・特徴から環境設定、アプリケーションの作成、業務用として応用できるところまで徹底解説していきます
小山博史(こやま ひろし)
情報家電、コンピュータと教育の研究に従事する傍ら、オープンソースソフトウェア、Java技術の普及のための活動を行っている。長野県の地域コミュニティである、SSS(G)やbugs(J)の活動へも参加している。
著書に「基礎Java」(インプレス)、共著に「Javaコレクションフレームワーク」(ソフトバンククリエイティブ)、そのほかに雑誌執筆多数。
Copyright © ITmedia, Inc. All Rights Reserved.