チュートリアル: サブプロトコルを使用して、WebSocket クライアント間でメッセージを発行およびサブスクライブする
- [アーティクル]
-
-
チャット アプリの構築チュートリアルでは、WebSocket API を使用して Azure Web PubSub でデータを送受信する方法について説明しました。 クライアントがサービスと通信する際に、プロトコルが必要ないことが分かります。 たとえば、任意の種類のデータを使用して WebSocket.send()
送信でき、サーバーは、そのまま受信します。 WebSocket API プロセスは簡単に使用できますが、機能は制限されています。 たとえば、サーバーにイベントを送信するときにイベント名を指定したり、サーバーに送信する代わりにメッセージを他のクライアントに発行したりすることはできません。 このチュートリアルでは、サブプロトコルを使用してクライアントの機能を拡張する方法について説明します。
このチュートリアルでは、次の作業を行う方法について説明します。
- Azure Web PubSub サービス インスタンスを作成する
- 完全な URL を生成して WebSocket 接続を確立する
- サブプロトコルを使用して WebSocket クライアント間でメッセージを発行する
Azure サブスクリプションをお持ちでない場合は、開始する前に Azure 無料アカウントを作成してください。
前提条件
- このセットアップには、Azure CLI のバージョン 2.22.0 以降が必要です。 Azure Cloud Shell を使用している場合は、最新バージョンが既にインストールされています。
Azure Web PubSub インスタンスを作成する
リソース グループを作成する
リソース グループとは、Azure リソースのデプロイと管理に使用する論理コンテナーです。 az group create コマンドを使用して、myResourceGroup
という名前のリソース グループを eastus
の場所に作成します。
az group create --name myResourceGroup --location EastUS
Web PubSub インスタンスを作成する
az extension add を実行して、webpubsub 拡張機能をインストールするか、最新バージョンにアップグレードします。
az extension add --upgrade --name webpubsub
Azure CLI の az webpubsub create コマンドを使用して、作成したリソース グループに Web PubSub を作成します。 次のコマンドは、EastUS のリソース グループ myResourceGroup の下に "無料の" Web PubSub リソースを作成します。
重要
Web PubSub リソースには、それぞれ一意の名前を付ける必要があります。 次の例では、<your-unique-resource-name> をお使いの Web PubSub の名前に置き換えてください。
az webpubsub create --name "<your-unique-resource-name>" --resource-group "myResourceGroup" --location "EastUS" --sku Free_F1
このコマンドの出力では、新しく作成したリソースのプロパティが表示されます。 次の 2 つのプロパティをメモしておきます。
- Resource Name: 上記の
--name
パラメーターに指定した名前です。
- hostName: この例では、ホスト名は
<your-unique-resource-name>.webpubsub.azure.com/
です。
この時点で、お使いの Azure アカウントのみが、この新しいリソースで任意の操作を実行することを許可されています。
将来使用するために ConnectionString を取得する
重要
接続文字列には、アプリケーションが Azure Web PubSub サービスにアクセスするために必要な認可情報が含まれています。 接続文字列内のアクセス キーは、サービスのルート パスワードに似ています。 運用環境では、アクセス キーは常に慎重に保護してください。 キーを安全に管理およびローテーションするには、Azure Key Vault を使用します。 アクセス キーを他のユーザーに配布したり、ハードコーディングしたり、他のユーザーがアクセスできるプレーンテキストで保存したりしないでください。 キーが侵害された可能性があると思われる場合は、キーをローテーションしてください。
Azure CLI の az webpubsub key コマンドを使用して、サービスの ConnectionString を取得します。 プレースホルダー <your-unique-resource-name>
を実際の Azure Web PubSub インスタンスの名前に置き換えます。
az webpubsub key show --resource-group myResourceGroup --name <your-unique-resource-name> --query primaryConnectionString --output tsv
後で使うために接続文字列をコピーします。
フェッチされた ConnectionString をコピーし、このチュートリアルの後半で値 <connection_string>
として使用します。
プロジェクトのセットアップ
前提条件
サブプロトコルの使用
クライアントは、特定のサブプロトコルを使用して WebSocket 接続を開始できます。 Azure Web PubSub サービスでは、json.webpubsub.azure.v1
と呼ばれるサブプロトコルがサポートされています。これにより、クライアントはアップストリーム サーバーにラウンド トリップすることなく、発行/サブスクライブを直接実行できます。 サブプロトコルの詳細については、「Azure Web PubSub でサポートされる JSON WebSocket サブプロトコル」をご覧ください。
他のプロトコル名を使用すると、それはサービスによって無視され、接続イベント ハンドラー内のサーバーにパススルーされます。そのため、独自のプロトコルを構築することができます。
それでは、json.webpubsub.azure.v1
サブプロトコルを使用して Web アプリケーションを作成しましょう。
依存関係のインストール
mkdir logstream
cd logstream
dotnet new web
dotnet add package Microsoft.Extensions.Azure
dotnet add package Azure.Messaging.WebPubSub
mkdir logstream
cd logstream
npm init -y
npm install --save express
npm install --save ws
npm install --save node-fetch
npm install --save @azure/web-pubsub
mkdir logstream
cd logstream
# Create venv
python -m venv env
# Active venv
source ./env/bin/activate
pip install azure-messaging-webpubsubservice
Javalin Web フレームワークを使用して Web ページをホストします。
まず、Maven を使用して新しいアプリ logstream-webserver
を作成し、logstream-webserver フォルダーに切り替えます。
mvn archetype:generate --define interactiveMode=n --define groupId=com.webpubsub.tutorial --define artifactId=logstream-webserver --define archetypeArtifactId=maven-archetype-quickstart --define archetypeVersion=1.4
cd logstream-webserver
Azure Web PubSub SDK とjavalin
Web フレームワークの依存関係を pom.xml
の dependencies
ノードに追加しましょう。
javalin
: Java 用の単純な Web フレームワーク
slf4j-simple
: Java 用ロガー
azure-messaging-webpubsub
: Azure Web PubSub を使用するためのサービス クライアント SDK
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-messaging-webpubsub</artifactId>
<version>1.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.javalin/javalin -->
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin</artifactId>
<version>3.13.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.30</version>
</dependency>
/negotiate
API と Web ページをホストするサーバー側を作成します。
下のコードを使用して Program.cs
を更新します。
AddAzureClients
を使ってサービス クライアントを追加し、構成から接続文字列を読み取ります。
- 静的ファイルをサポートするために、
app.Run();
の前に app.UseStaticFiles();
を追加します。
app.MapGet
を更新して、/negotiate
要求を持つクライアント アクセス トークンを生成します。
using Azure.Messaging.WebPubSub;
using Microsoft.Extensions.Azure;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAzureClients(s =>
{
s.AddWebPubSubServiceClient(builder.Configuration["Azure:WebPubSub:ConnectionString"], "stream");
});
var app = builder.Build();
app.UseStaticFiles();
app.MapGet("/negotiate", async context =>
{
var service = context.RequestServices.GetRequiredService<WebPubSubServiceClient>();
var response = new
{
url = service.GetClientAccessUri(roles: new string[] { "webpubsub.sendToGroup.stream", "webpubsub.joinLeaveGroup.stream" }).AbsoluteUri
};
await context.Response.WriteAsJsonAsync(response);
});
app.Run();
server.js
を作成し、以下のコードを追加します。
const express = require('express');
const { WebPubSubServiceClient } = require('@azure/web-pubsub');
let service = new WebPubSubServiceClient(process.env.WebPubSubConnectionString, 'stream');
const app = express();
app.get('/negotiate', async (req, res) => {
let token = await service.getClientAccessToken({
roles: ['webpubsub.sendToGroup.stream', 'webpubsub.joinLeaveGroup.stream']
});
res.send({
url: token.url
});
});
app.use(express.static('public'));
app.listen(8080, () => console.log('server started'));
server.py
を作成し、/negotiate
API と Web ページをホストします。
import json
import sys
from http.server import HTTPServer, SimpleHTTPRequestHandler
from azure.messaging.webpubsubservice import WebPubSubServiceClient
service = WebPubSubServiceClient.from_connection_string(sys.argv[1], hub='stream')
class Resquest(SimpleHTTPRequestHandler):
def do_GET(self):
if self.path == '/':
self.path = 'public/index.html'
return SimpleHTTPRequestHandler.do_GET(self)
elif self.path == '/negotiate':
roles = ['webpubsub.sendToGroup.stream',
'webpubsub.joinLeaveGroup.stream']
token = service.get_client_access_token(roles=roles)
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({
'url': token['url']
}).encode())
if __name__ == '__main__':
if len(sys.argv) != 2:
print('Usage: python server.py <connection-string>')
exit(1)
server = HTTPServer(('localhost', 8080), Resquest)
print('server started')
server.serve_forever()
/src/main/java/com/webpubsub/tutorial ディレクトリに移動し、App.java ファイルをエディタで開き、Javalin.create
を使用して静的ファイルを提供します。
package com.webpubsub.tutorial;
import com.azure.messaging.webpubsub.WebPubSubServiceClient;
import com.azure.messaging.webpubsub.WebPubSubServiceClientBuilder;
import com.azure.messaging.webpubsub.models.GetClientAccessTokenOptions;
import com.azure.messaging.webpubsub.models.WebPubSubClientAccessToken;
import io.javalin.Javalin;
public class App {
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("Expecting 1 arguments: <connection-string>");
return;
}
// create the service client
WebPubSubServiceClient service = new WebPubSubServiceClientBuilder()
.connectionString(args[0])
.hub("chat")
.buildClient();
// start a server
Javalin app = Javalin.create(config -> {
config.addStaticFiles("public");
}).start(8080);
// Handle the negotiate request and return the token to the client
app.get("/negotiate", ctx -> {
GetClientAccessTokenOptions option = new GetClientAccessTokenOptions();
option.addRole("webpubsub.sendToGroup.stream");
option.addRole("webpubsub.joinLeaveGroup.stream");
WebPubSubClientAccessToken token = service.getClientAccessToken(option);
// return JSON string
ctx.result("{\"url\":\"" + token.getUrl() + "\"}");
return;
});
}
}
設定によっては、pom.xml で言語レベルを Java 8 に明示的に設定する必要がある場合があります。 次のスニペットを追加します。
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
Web ページの作成
以下のコンテンツを含む HTML ページを作成し、wwwroot/index.html
として保存します。
以下のコンテンツを含む HTML ページを作成し、public/index.html
として保存します。
以下のコンテンツを含む HTML ページを作成し、public/index.html
として保存します。
以下の内容の HTML ページを作成し /src/main/resources/public/index.html に保存します。
<html>
<body>
<div id="output"></div>
<script>
(async function () {
let res = await fetch('/negotiate')
let data = await res.json();
let ws = new WebSocket(data.url, 'json.webpubsub.azure.v1');
ws.onopen = () => {
console.log('connected');
};
let output = document.querySelector('#output');
ws.onmessage = event => {
let d = document.createElement('p');
d.innerText = event.data;
output.appendChild(d);
};
})();
</script>
</body>
</html>
上記のコードを使うと、サービスへの接続が行われ、受信したメッセージがページに出力されます。 主な変更は、WebSocket 接続の作成時にサブプロトコルを指定することです。
サーバーを実行する
.NET Core 用の Secret Manager ツールを使用して接続文字列を設定します。 <connection_string>
を、前の手順でフェッチされたものに置き換えて下のコマンドを実行し、ブラウザで http://localhost:5000/index.html を開きます。
dotnet user-secrets init
dotnet user-secrets set Azure:WebPubSub:ConnectionString "<connection-string>"
dotnet run
<connection-string>
を、前の手順でフェッチされた ConnectionString に置き換えて下のコマンドを実行し、ブラウザで http://localhost:8080 を開きます。
export WebPubSubConnectionString="<connection-string>"
node server
<connection-string>
を、前の手順でフェッチされた ConnectionString に置き換えて下のコマンドを実行し、ブラウザで http://localhost:8080 を開きます。
python server.py "<connection-string>"
<connection-string>
を、前の手順でフェッチされた ConnectionString に置き換えて下のコマンドを実行し、ブラウザで http://localhost:8080 を開きます。
mvn compile & mvn package & mvn exec:java -Dexec.mainClass="com.webpubsub.tutorial.App" -Dexec.cleanupDaemonThreads=false -Dexec.args="'<connection_string>'"
Chrome を使用している場合は、F12 キーを押すか、右クリックして ->Inspect ->Developer Tools を選択し、[ネットワーク] タブを選択します。Web ページを読み込み、WebSocket 接続が確立されていることを確認できます。 WebSocket 接続を検査するために選択すると、クライアントで次 connected
のイベント メッセージが受信されていることがわかります。 このクライアントに connectionId
を生成できることが分かります。
{"type":"system","event":"connected","userId":null,"connectionId":"<the_connection_id>"}
サブプロトコルを使用すると、接続が connected
のときに接続のメタデータを取得できます。
クライアントはプレーン テキストではなく JSON メッセージを受信するようになりました。 JSON メッセージには、メッセージの種類やソースなどの詳細情報が含まれています。 そのため、この情報を使用して、メッセージに対してより多くの処理を実行できます (たとえば、別のソースからの場合は、別のスタイルでメッセージを表示するなど)。これは、後のセクションで説明します。
クライアントからメッセージを発行する
チャット アプリのビルドに関するチュートリアルでは、クライアントが WebSocket 接続を介して Web PubSub サービスにメッセージを送信すると、サービスによってサーバー側でユーザー イベントがトリガーされます。 サブプロトコルを使用すると、クライアントは JSON メッセージを送信することでより多くの機能を持ちます。 たとえば、Web PubSub サービスを介してクライアントから他のクライアントに直接メッセージを発行できます。
これは、大量のデータを他のクライアントにリアルタイムでストリーミングする場合に便利です。 この機能を使用し、コンソール ログをリアルタイムでブラウザーにストリーミングできる、ログ ストリーミング アプリケーションを構築しましょう。
ストリーミング プログラムの作成
stream
プログラムを作成します。
mkdir stream
cd stream
dotnet new console
次の内容を使用して Program.cs
を更新します。
using System;
using System.Net.Http;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace stream
{
class Program
{
private static readonly HttpClient http = new HttpClient();
static async Task Main(string[] args)
{
// Get client url from remote
var stream = await http.GetStreamAsync("http://localhost:5000/negotiate");
var url = (await JsonSerializer.DeserializeAsync<ClientToken>(stream)).url;
var client = new ClientWebSocket();
client.Options.AddSubProtocol("json.webpubsub.azure.v1");
await client.ConnectAsync(new Uri(url), default);
Console.WriteLine("Connected.");
var streaming = Console.ReadLine();
while (streaming != null)
{
if (!string.IsNullOrEmpty(streaming))
{
var message = JsonSerializer.Serialize(new
{
type = "sendToGroup",
group = "stream",
data = streaming + Environment.NewLine,
});
Console.WriteLine("Sending " + message);
await client.SendAsync(Encoding.UTF8.GetBytes(message), WebSocketMessageType.Text, true, default);
}
streaming = Console.ReadLine();
}
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, null, default);
}
private sealed class ClientToken
{
public string url { get; set; }
}
}
}
次の内容を使用して stream.js
を作成します。
const WebSocket = require('ws');
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
async function main() {
let res = await fetch(`http://localhost:8080/negotiate`);
let data = await res.json();
let ws = new WebSocket(data.url, 'json.webpubsub.azure.v1');
let ackId = 0;
ws.on('open', () => {
process.stdin.on('data', data => {
ws.send(JSON.stringify({
type: 'sendToGroup',
group: 'stream',
ackId: ++ackId,
dataType: 'text',
data: data.toString()
}));
});
});
ws.on('message', data => console.log("Received: %s", data));
process.stdin.on('close', () => ws.close());
}
main();
上記のコードは、サービスへの WebSocket 接続を作成し、データを受信するたびに ws.send()
を使用してそのデータを発行します。 他のグループに発行するには、type
を sendToGroup
に設定し、メッセージでグループ名を指定します。
stream
プログラム用の別の bash ウィンドウを開き、websockets
依存関係をインストールします。
mkdir stream
cd stream
# Create venv
python -m venv env
# Active venv
source ./env/bin/activate
pip install websockets
次の内容を使用して stream.py
を作成します。
import asyncio
import sys
import threading
import time
import websockets
import requests
import json
async def connect(url):
async with websockets.connect(url, subprotocols=['json.webpubsub.azure.v1']) as ws:
print('connected')
id = 1
while True:
data = input()
payload = {
'type': 'sendToGroup',
'group': 'stream',
'dataType': 'text',
'data': str(data + '\n'),
'ackId': id
}
id = id + 1
await ws.send(json.dumps(payload))
await ws.recv()
if __name__ == '__main__':
res = requests.get('http://localhost:8080/negotiate').json()
try:
asyncio.get_event_loop().run_until_complete(connect(res['url']))
except KeyboardInterrupt:
pass
上記のコードは、サービスへの WebSocket 接続を作成し、データを受信するたびに ws.send()
を使用してそのデータを発行します。 他のグループに発行するには、type
を sendToGroup
に設定し、メッセージでグループ名を指定します。
別のターミナルを使用してルート フォルダーに戻り、ストリーミング コンソール アプリ logstream-streaming
を作成して、logstream-streaming フォルダーに切り替えます。
mvn archetype:generate --define interactiveMode=n --define groupId=com.webpubsub.quickstart --define artifactId=logstream-streaming --define archetypeArtifactId=maven-archetype-quickstart --define archetypeVersion=1.4
cd logstream-streaming
pom.xml
の dependencies
ノードに HttpClient の依存関係を追加してみましょう。
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
ここで、WebSocket を使用してサービスに接続します。 /src/main/java/com/webpubsub/quickstart ディレクトリに移動し、エディタで App.java ファイルをオープンして、下のコードに置き換えます。
package com.webpubsub.quickstart;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.WebSocket;
import java.util.concurrent.CompletionStage;
import com.google.gson.Gson;
public class App
{
public static void main( String[] args ) throws IOException, InterruptedException
{
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://localhost:8080/negotiate"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
Gson gson = new Gson();
String url = gson.fromJson(response.body(), Entity.class).url;
WebSocket ws = HttpClient.newHttpClient().newWebSocketBuilder().subprotocols("json.webpubsub.azure.v1")
.buildAsync(URI.create(url), new WebSocketClient()).join();
int id = 0;
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String streaming = reader.readLine();
App app = new App();
while (streaming != null && !streaming.isEmpty()){
String frame = gson.toJson(app.new GroupMessage(streaming + "\n", ++id));
System.out.println("Sending: " + frame);
ws.sendText(frame, true);
streaming = reader.readLine();
}
}
private class GroupMessage{
public String data;
public int ackId;
public final String type = "sendToGroup";
public final String group = "stream";
GroupMessage(String data, int ackId){
this.data = data;
this.ackId = ackId;
}
}
private static final class WebSocketClient implements WebSocket.Listener {
private WebSocketClient() {
}
@Override
public void onOpen(WebSocket webSocket) {
System.out.println("onOpen using subprotocol " + webSocket.getSubprotocol());
WebSocket.Listener.super.onOpen(webSocket);
}
@Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
System.out.println("onText received " + data);
return WebSocket.Listener.super.onText(webSocket, data, last);
}
@Override
public void onError(WebSocket webSocket, Throwable error) {
System.out.println("Bad day! " + webSocket.toString());
WebSocket.Listener.super.onError(webSocket, error);
}
}
private static final class Entity {
public String url;
}
}
- pom.xml ファイルが格納されているディレクトリに移動し、次のコマンドを使用してプロジェクトを実行します
mvn compile & mvn package & mvn exec:java -Dexec.mainClass="com.webpubsub.quickstart.App" -Dexec.cleanupDaemonThreads=false
新しい概念 "グループ" がここにあることがわかります。 グループは、接続のグループにメッセージを発行できる、ハブの論理的な概念です。 ハブでは、複数のグループを使用でき、1 つのクライアントは同時に複数のグループをサブスクライブできます。 サブプロトコルを使用する場合には、ハブ全体にブロードキャストするのではなく、グループにのみ発行できます。 用語の詳細については、「基本的な概念」をご覧ください。
ここではグループを使用するため、ws.onopen
コールバック内で WebSocket 接続を確立する際に、Web ページ index.html
を更新し、グループに参加する必要もあります。
let ackId = 0;
ws.onopen = () => {
console.log('connected');
ws.send(JSON.stringify({
type: 'joinGroup',
group: 'stream',
ackId: ++ackId
}));
};
クライアントがグループに参加しているのを確認するには、joinGroup
型のメッセージを送信します。
また、ws.onmessage
コールバック ロジックを少々更新して、JSON 応答を解析し、stream
グループからのメッセージのみを出力するようにして、ライブ ストリーム プリンターとして機能させます。
ws.onmessage = event => {
let message = JSON.parse(event.data);
if (message.type === 'message' && message.group === 'stream') {
let d = document.createElement('span');
d.innerText = message.data;
output.appendChild(d);
window.scrollTo(0, document.body.scrollHeight);
}
};
セキュリティ上の理由から、既定では、クライアントは、それ自体でグループに発行したり、またはグループをサブスクライブすることはできません。 そのため、トークンの生成時にクライアントに設定 roles
されていることがわかります。
Startup.cs
のGenerateClientAccessUri
で、roles
を下のように設定します。
service.GenerateClientAccessUri(roles: new string[] { "webpubsub.sendToGroup.stream", "webpubsub.joinLeaveGroup.stream" })
server.js
のgetClientAccessToken
で、roles
を下のように追加します。
app.get('/negotiate', async (req, res) => {
let token = await service.getClientAccessToken({
roles: ['webpubsub.sendToGroup.stream', 'webpubsub.joinLeaveGroup.stream']
});
...
});
アクセス トークン生成プロセス中にクライアント server.py
に正しいロールを設定します。
roles = ['webpubsub.sendToGroup.stream',
'webpubsub.joinLeaveGroup.stream']
token = service.get_client_access_token(roles=roles)
アクセス トークン生成プロセス中にクライアント App.java
に正しいロールを設定します。
GetClientAccessTokenOptions option = new GetClientAccessTokenOptions();
option.addRole("webpubsub.sendToGroup.stream");
option.addRole("webpubsub.joinLeaveGroup.stream");
WebPubSubClientAccessToken token = service.getClientAccessToken(option);
最後に、適切に表示されるようにするため、index.html
にスタイルを適用します。
<html>
<head>
<style>
#output {
white-space: pre;
font-family: monospace;
}
</style>
</head>
次に、次のコードを実行し、任意のテキストを入力すると、リアルタイムでブラウザーに表示されます。
ls -R | dotnet run
# Or call `dir /s /b | dotnet run` when you are using CMD under Windows
または速度を低下させ、データがリアル タイムでブラウザーにストリーミングされるのを確認します。
for i in $(ls -R); do echo $i; sleep 0.1; done | dotnet run
このチュートリアルの完成したコード サンプルは、こちらにあります。
node stream
または、このアプリを使用し、別のコンソール アプリからの出力をパイプしてブラウザーにストリーミングすることもできます。 例:
ls -R | node stream
# Or call `dir /s /b | node stream` when you are using CMD under Windows
または速度を低下させ、データがリアル タイムでブラウザーにストリーミングされるのを確認します。
for i in $(ls -R); do echo $i; sleep 0.1; done | node stream
このチュートリアルの完成したコード サンプルは、こちらにあります。
これで、任意のテキストを実行 python stream.py
して入力できるようになり、リアルタイムでブラウザーに表示されます。
または、このアプリを使用し、別のコンソール アプリからの出力をパイプしてブラウザーにストリーミングすることもできます。 例:
ls -R | python stream.py
# Or call `dir /s /b | python stream.py` when you are using CMD under Windows
または速度を低下させ、データがリアル タイムでブラウザーにストリーミングされるのを確認します。
for i in $(ls -R); do echo $i; sleep 0.1; done | python stream.py
このチュートリアルの完成したコード サンプルは、こちらにあります。
次のコードを実行し、任意のテキストを入力すると、リアルタイムでブラウザーに表示されます。
mvn compile & mvn package & mvn exec:java -Dexec.mainClass="com.webpubsub.quickstart.App" -Dexec.cleanupDaemonThreads=false
このチュートリアルの完全なコード サンプルは、こちらにあります。
次のステップ
このチュートリアルでは、Web PubSub サービスに接続する方法と、サブプロトコルを使用して接続されたクライアントにメッセージを発行する方法の基本的なアイデアを提供します。
サービスの使用方法の詳細については、他のチュートリアルを参照してください。