こんにちは
この記事では、DartでWebソケットを操作する方法を示すために、Dartで簡単なWebSocketチャットを作成する方法を説明します。 アプリケーションコードは
githubで入手でき、その操作の例は
http://simplechat.rudart.inにあります。
アプリケーションは、サーバーとクライアントの2つの部分で構成されます。 サーバー部分を詳細に分析し、クライアントからは、接続の処理に責任を負うもののみを検討します。
アプリケーションの要件は非常に単純です-ユーザーからすべての、または選択したチャット参加者のみにメッセージを送信します。
アプリケーション設定
すべてのアプリケーション設定と定数は、
common/lib/common.dartファイルに保存されます。 このファイルには、
simplechat.commonライブラリーの定義が含まれています。
library simplechat.common; const String ADDRESS = 'simplechat.rudart.in'; const int PORT = 9224; const String SYSTEM_CLIENT = 'Simple Chat';
ファイル自体をパッケージとして接続します。 相対パスを使用すると、アプリケーションを
pub buildとき(
pub build )、
pubからエラーを取得
できます 。
例外:ビルド環境の外にあるため、{file}を読み取ることができません 。
マシンのどこかにあるパッケージを接続するために、
pub pathdependencyを使用し
ます 。 これを行うには、
pubspec.yamlファイルの
dependenciesセクションにパッケージ
pubspec.yaml定義を
pubspec.yamlだけです。
dependencies: simplechat.common: path: ./common
pubspec.yamlファイルの内容全体を提供するわけではありません(ただし、
githubで確認できます)。 また、
pubspec.yamlファイルを
commonディレクトリに追加する必要があります。ここで、パッケージの名前を単に指定します。
name: simplechat.common
サーバー
サーバーファイルは
binフォルダーにあります。
main.dartファイルにはサーバーへのエントリポイント
main.dart 、
main.dartファイルにはサーバー
server.dartクラスが
server.dartます。
main.dartファイルの内容を見てみましょう。
一般的なサーバー操作スキーム
サーバーが一般的にどのように機能するかについて話しましょう。 サーバーで最初に行うことは、サーバーを起動することです。 起動時に、ポート
9224リッスンを開始します。
新しいユーザーがこのポートにリクエストを送信すると、サーバーはそのポート用のWebSocket接続を開き、名前を生成し、名前と接続を開いている接続でハッシュに保存します。 その後、クライアントはこの接続でメッセージを送信できるようになります。 サーバーは、これらのメッセージを他のユーザーに送信できるだけでなく、クライアントの接続および切断に関する通知を送信できます。
ユーザーが接続を閉じると、サーバーはアクティブな接続のハッシュからその接続を削除します。
サーバーエントリポイント
bin/main.dart最初に、
simplechat.binライブラリーであると定義します。 サーバーが機能するためには、
dart:async 、
dart:convert 、
dart:ioライブラリ、
routeパッケージ(
pubを介して入力)、およびアプリケーション設定ファイルを接続する必要があります。 また、
bin/main.dartには、サーバーのメインコードを含むファイル
bin/main.dartを含めます(これについては後で検討します)。
main()関数で、サーバーのインスタンスを作成して実行します。
library simplechat.bin; import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:route/server.dart' show Router; import 'package:simplechat.common/common.dart'; part 'server.dart'; main() { Server server = new Server(ADDRESS, PORT); server.bind(); }
サーバー基本クラス、ポート盗聴
以下は基本的なサーバーコードで、単に目的のポートにバインドされます。
part of simplechat.bin; class Server { int port; var address; HttpServer _server; Router _router; Map<String, WebSocket> connections = new Map<String, WebSocket>(); int generalCount = 1; Server([ this.address = '127.0.0.1', this.port = 9224 ]); bind() { HttpServer.bind(address, port).then(connectServer); } connectServer(server) { print('Chat server is running on "$address:$port"'); _server = server; bindRouter(); } }
connectServer()関数の最後で、ルーターを構成する関数は
bindRouter()ます。これについては以下で説明します。
ルーターの構成とWebSocket接続の作成
ルーターを構成するには、
bindRouter()関数を作成します。
WebSocketTransformerを使用して着信ストリームを
/変更し、
createWs()関数でリッスンします。
bindRouter() { _router = new Router(_server); _router.serve('/') .transform(new WebSocketTransformer()) .listen(this.createWs); } createWs(WebSocket webSocket) { String connectionName = 'user_$generalCount'; ++generalCount; connections.putIfAbsent(connectionName, () => webSocket); }
createWs()関数では、
createWs() user_{counter}スキームに従って接続の名前を生成し、この接続を
connections保存し
connections 。
サーバーからのメッセージ構造とメッセージ作成機能
サーバーは、次のキーを持つメッセージをMapオブジェクト(またはjsonでの表現)として送信します。
- from-メッセージの送信元。
- message-メッセージテキスト。
- オンライン - オンラインのユーザー数。
このようなメッセージを作成する関数は次のとおりです。
String buildMessage(String from, String message) { Map<String, String> data = { 'from': from, 'message': message, 'online': connections.length }; return JSON.encode(data); }
サーバーからメッセージを送信する
クライアントにメッセージを送信するには、
WebSocketクラスの
add()メソッドを使用する必要があります。 以下は、ユーザーにメッセージを送信する関数です。
void send(String to, String message) { connections[to].add(message); }
サーバーは、すべてのアクティブなクライアントにユーザーの接続または切断に関する通知を送信できます。 この機能を見てみましょう。
notifyAbout(String connectionName, String message)関数
notifyAbout(String connectionName, String message)名とメッセージ(接続または切断に関する
notifyAbout(String connectionName, String message)ます。 この関数は、この通知の送信者に加えて、すべてのアクティブなクライアントに通知します。 つまり
user_3が参加した場合、それ以外のすべてのユーザーに通知が送信されます。 特定の条件でクライアントをフィルタリングするには(この場合、現在のクライアントと一致しないすべてのクライアントの名前を取得する必要があります
) 、
Iterable抽象クラスの
where()メソッドを使用します。
notifyAbout(String connectionName, String message) { String jdata = buildMessage(SYSTEM_CLIENT, message); connections.keys .where((String name) => name != connectionName) .forEach((String name) { send(name, jdata); }); }
また、新しいユーザーに参加した後、彼を歓迎します。
void sendWelcome(String connectionName) { String jdata = buildMessage(SYSTEM_CLIENT, 'Welcome to chat!'); send(connectionName, jdata); }
ユーザーからの着信メッセージを処理して、すべての(または指定された)チャット参加者に送信する機能を見てみましょう。
sendMessage(String from, String message)関数は、送信者の名前とそのメッセージを受け入れます。 メッセージ本文(
message )がマスク
@{user_name}によって受信者の名前を指定している場合、メッセージは受信者にのみ配信されます。
sendMessage関数
sendMessage見てみましょう:
sendMessage(String from, String message) { String jdata = buildMessage(from, message);
ユーザーが接続を閉じると、アクティブな接続のリストから削除する必要があります。
closeConnection(String connectionName)関数は、閉じられた接続の名前を受け入れ、接続リストから削除します。
closeConnection(String connectionName) { if (connections.containsKey(connectionName)) { connections.remove(connectionName); } }
接続リスナーに機能を追加する
私たちが今持っているすべてを要約します。
createWs関数
createWsユーザー接続を
createWsます。
send指定されたユーザーにメッセージを送信します。
sendWelcome新しいユーザーに挨拶メッセージを送信します。
notifyAbout開始者のアクション(接続/切断)をチャット参加者(開始者を除く)に通知します。
sendMessageすべてまたは指定されたユーザーのみにメッセージを送信します。
createWs関数を変更して、
createWsすべてを使用できるようにしましょう。 リストへの接続の追加で最後に停止したとき。 その後、他のすべてのチャット参加者に新しいユーザーについて通知し、新しいユーザーに挨拶メッセージを送信する必要があります。
次に、ユーザーからのメッセージへのユーザーのWebSocket接続をリッスンし、参加者にメッセージを送信する必要があります。 また、websocket接続を閉じるハンドラーを追加します。このハンドラーでは、リストから削除し、すべての参加者に切断するよう通知します。
createWs(WebSocket webSocket) { String connectionName = 'user_$generalCount'; ++generalCount; connections.putIfAbsent(connectionName, () => webSocket);
以上で、簡単なサーバーの準備が整いました。 それでは、クライアント側に移りましょう。
お客様
ここで
は、クライアント部分のレイアウト とメッセージの
表示 については説明しません。 このパートでは、サーバーへのWebSocket接続を開き、メッセージを送受信する方法についてのみ説明します。
クライアントアプリケーションのエントリポイント
クライアントアプリケーションのエントリポイントは、
web/dart/index.dartファイルにあります。 その内容を見てみましょう:
library simplechat.client; import 'dart:html'; import 'dart:convert'; import 'package:simplechat.common/common.dart'; part './views/message_view.dart'; part './controllers/web_socket_controller.dart'; main() { WebSocketController wsc = new WebSocketController('ws://$ADDRESS:$PORT', '#messages', '#userText .text', '#online'); }
最初の行では、ライブラリを宣言します。 次に、必要なファイルとライブラリの一部を接続します。
./views/message_view.dartファイルに
./views/message_view.dartメッセージの表示を担当する
MessageViewクラスの定義が
./views/message_view.dartます。 考慮しません(コードは
githubで表示できます)。
./controllers/web_socket_controller.dartファイル
./controllers/web_socket_controller.dartは、
WebSocketControllerクラスの定義が
./controllers/web_socket_controller.dartます。これについては、さらに詳しく説明します。
main()関数では、このコントローラーのインスタンスが常に作成されます。
WebSocketController-クラスコンストラクターと接続の作成
WebSocketControllerクラスのプロパティとコンストラクターを見てみましょう。
class WebSocketController { WebSocket ws; HtmlElement output; TextAreaElement userInput; DivElement online; WebSocketController(String connectTo, String outputSelector, String inputSelector, String onlineSelector) { output = querySelector(outputSelector); userInput = querySelector(inputSelector); online = querySelector(onlineSelector); ws = new WebSocket(connectTo); ws.onOpen.listen((e){ showMessage('onnection is established', SYSTEM_CLIENT); bindSending(); }); ws.onClose.listen((e) { showMessage('Connection closed', SYSTEM_CLIENT); }); ws.onMessage.listen((MessageEvent e) { processMessage(e.data); }); ws.onError.listen((e) { showMessage('Connection error', SYSTEM_CLIENT); }); }
このコードは、
WebSocketControllerに次のプロパティがあることを示しています。
WebSocket wsここにwebsocket接続を保存します。HtmlElement outputメッセージが出力される要素。TextAreaElement userInputユーザーがメッセージを入力するテキスト領域。DivElement online -アクティブなユーザーの数が表示される要素。
クラスのコンストラクターは、websocket接続を開くことができるアドレス、
userInputセレクター、
userInputおよび
online要素を
userInput online 。 最初の段階で、彼はツリー内の要素を見つけます。 次に、
WebSocketコンストラクターを使用して、サーバーへのwebsocket接続が作成されます。
ws = new WebSocket(connectTo);
次に、イベントハンドラーを接続に割り当てます。
接続が正常に確立されると、
onOpenイベントが発生します。 そのハンドラーは、接続が確立されたことを示すメッセージを表示し、リスナーをメッセージ入力要素のキーストロークに配置して、
Enterを押すとメッセージが送信されるようにします。
bindSending()関数のコードは次の
bindSending()です。
bindSending() { userInput.onKeyUp.listen((KeyboardEvent key) { if (key.keyCode == 13) { key.stopPropagation(); sendMessage(userInput.value); userInput.value = ''; } }); }
keyUpイベント
keyUpの本文で、メッセージの送信に関与している
sendMessage(String message)関数の呼び出しに注目できます。
WebSocket接続を介したメッセージの
送信は、
WebSocketクラスの
send()メソッドを使用して行われます。 この関数のコードは次のとおりです。
sendMessage(String message) { Map data = { 'message': message }; String jdata = JSON.encode(data); ws.send(jdata); }
接続が閉じられると、
onCloseイベントが発生します。 このイベントのハンドラーは、接続が切断されたことを示すメッセージを表示するだけです。
onMessageイベントは、サーバーからメッセージを受信すると発生します。 リスナーには
MessageEventオブジェクトが渡されます。 このイベントのハンドラーは、サーバーから受信したデータを
processMessage関数に渡します
processMessage関数は、単にメッセージを表示します。 彼女のコードは次のとおりです。
processMessage(String message) { var data = JSON.decode(message); showOnline(data['online']); showMessage(data['message'], data['from']); }
showOnlineおよび
showMessage関数コードを引用しません。 特に興味深いことは何も起こりません。 ただし、コンテンツに興味がある場合は、
githubで完全なコントローラーコードをいつでも見つけることができます。
以上です。 これがすべてクライアント部分の主要な機能です。
動作中のアプリケーションは、
http :
//simplechat.rudart.inで確認できます。
間違いや不正確な点を見つけた場合はお知らせください。すみやかにすべてを修正します。