はじめに
Node.js で WebSocketサーバーを作る時などによく使っているのパッケージの「ws」について、情報を見ていて気になった「createWebSocketStream」の話です。
GitHub上で言うと、以下の部分になります。
●websockets/ws: Simple to use, blazing fast and thoroughly tested WebSocket client and server for Node.js
https://github.com/websockets/ws?tab=readme-ov-file#use-the-nodejs-streams-api
今まで、自分は使ったことがないものだったので、今回軽く試してみました。
実際に試してみる
試す内容について、上記のストリームの処理になりますが、その実装でサーバー側もクライアント側も、両方とも自前で用意する形にしてみます。
上記のサンプルでは、サーバー側は websocket-echo.com というものが指定されているところを、自分で用意した WebSocketサーバーを使う形でやってみます。
下準備
ここから実際に試していきます。下準備はパッケージのインストールのみです。
npm i ws
これで準備は整いました。
コード
ここからコードを準備してみます。
クライアント側
まずはクライアント側です。内容はシンプルに、上記のサンプルの接続先をローカルの自前のサーバーにする、ということだけ対応したものとします。
具体的には以下のとおりで、接続先を ws://localhost:8080
としています。
import WebSocket, { createWebSocketStream } from "ws";
// const ws = new WebSocket('wss://websocket-echo.com/');
const ws = new WebSocket("ws://localhost:8080");
const duplex = createWebSocketStream(ws, { encoding: "utf8" });
duplex.on("error", console.error);
duplex.pipe(process.stdout);
process.stdin.pipe(duplex);
サーバー側
次はサーバー側です。
基本的には、シンプルな WebSocketサーバーに、少しだけ手を加えたような以下になります。
import WebSocket, { WebSocketServer, createWebSocketStream } from "ws";
const wss = new WebSocketServer({ port: 8080 });
wss.on("connection", (ws) => {
const duplex = createWebSocketStream(ws, { encoding: "utf8" });
duplex.on("error", (err) => {
console.error("サーバー側ストリームでエラー:", err);
});
duplex.pipe(duplex);
duplex.on("data", (chunk) => {
console.log("サーバーで受信:", chunk);
});
});
console.log("WebSocket サーバーをポート 8080 で起動");
ちなみに、以前からよく使っていたシンプルな WebSocketサーバーの処理だと、以下のような実装になります。
import { WebSocketServer } from 'ws';
const wss = new WebSocketServer({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('error', console.error);
ws.on('message', function message(data) {
console.log('received: %s', data);
});
ws.send('something');
});
これら 2つの実装の差分としては、WebSocket関連の話では createWebSocketStream(ws, { encoding: "utf8" });
の部分が加わったくらいです。これにより、Node.jsネイティブの双方向ストリームを扱うことができるようです。
双方向ストリームについて
「双方向ストリーム」の duplex は、今回のコードでは createWebSocketStream(ws) を使って得られた「WebSocket をラップした Duplex ストリーム」になります。これは「Readable」と「Writable」の両方の機能を持ったものになるようです。
このため、コード内の duplex.pipe(duplex);
というシンプルな記述で、「Readable 部分による WebSocket のメッセージ受信」を「(WebSocket で受信したデータに関しての)Writable 部分による相手への WebSocket での送信」ということが一気にできる形になります。
動作させてみた時の様子
動作させてみた時の様子は以下のとおりです。
流れとしては「サーバー起動」⇒「クライアント実行」⇒「クライアント側から文字を送ると、サーバー側での受信文字列の出力 & クライアント側で文字列の出力(サーバー側に送って返ってきた文字列を受信して出力)」という感じです。
おわりに
今回、ws の情報に出てくる「createWebSocketStream」が気になり、それを用いたストリームの処理を Node.js で試してみました。
今回の内容だと、ありがたみが分かりにくいですが、「Node.js のストリームを扱える」という話について、以下の記事にあるようなメリットを出せる使い方ができそうです(※ 詳細は未確認)。
●Node.js Stream を使ってみる|ラキール公式|株式会社ラキールのエンジニアたちによるTECH BLOG
https://tech-blog.lakeel.com/n/n62073e6f3101
もう少し、今回の内容は周辺情報なども含め、技術情報を見ていければと思っています