ビジネスシーン
最近、リアルタイムで音声エスケープを行うビジネスシナリオがあり、リアルタイム性を考慮してWebSocketを使用して実現することにしました。
ビジネス シナリオは、クライアント A (携帯電話) の音声エスケープ結果がクライアント B (PC) にリアルタイムで同期されるというものです。これには、WebSocket を使用して A のエスケープ結果をサーバーに送信する必要があり、サーバーは A の音声エスケープ結果を受信します。情報を直接Bに同期してPushするため、単純な無差別放送とは異なります。
インターネット上の WebSocket の例を読んだところ、特定のクライアントにメッセージをプッシュする方法についての説明はほとんどなく、説明も間違っています。そこで、誰でもすぐに使える例を書くことにしました。
WebSocketの通信プロセス
まず、次の例の WebSocket サービスの通信プロセスを説明します
1. サーバーは WebSocket ポート サービスを開始します
2. 次に、クライアントは新しい WebSocket (サーバー アドレス、ws://127.0.0.1:5201/?userId=liubao など) に移動し、サーバーの wss.on('connection') に移動して接続を確立します。ペア 1 つが接続されています。全員が理解しやすいように、userId を URL に直接入力しました (実際のビジネス シナリオでは、通常、ヘッダーのトークンを使用してユーザーが誰であるかを分析します)。
3. サーバーは、この userId のリクエスト接続プールをクライアント配列に保存します。
4. この時点で、クライアントはサーバーにメッセージを送信し、それは ws.on('message') に進み、そこでデータを使用してクライアントから送信されたメッセージを受信します。
備考: クライアントから受信したデータはバイナリバッファ情報(バイナリ情報は従来のjson情報に比べて10倍高速)なので、データを印刷する際のバッファになります。
console.log('%s',data);
データ情報を取得する場合は、まず文字列に変換する必要があります。変換しないとバッファ配列情報となり、処理できません。
userId と送信するメッセージを含む json メッセージをクライアントから送信します。
例:
// 客户端A
{
"userId": "liubao", "message": "给liubao一个小爱心" }
// 客户端B
{
"userId": "bob", "message": "给你bob一个大铁锤" }
5. userId がある場合は接続プールを走査し、同じ userId 接続プールを見つけてメッセージをプッシュします。
最終効果
サーバーコード
次のコードをindex.jsファイルにコピーし、依存関係をインストールして実行します。
npm i ws
node index.js
import {
WebSocketServer } from 'ws';
const clients = []; // 与客户端建立的连接池
const wss = new WebSocketServer({
port: 5201 }); // 创建一个websocket服务
wss.on('connection', function connection(ws, request, client) {
let url = request.headers.origin + request.url; // example:ws://127.0.0.1:5201/?userId=liubao
let userId = getParam(url, 'userId');
if (userId) {
clients.push({
userId, ws: ws }); // 连接时只要url带userId参数,直接往客户端数组里塞入连接池信息
}
ws.on('message', function message(data, isBinary) {
// 得到客户端往服务端发送的消息
try {
let objMessage = JSON.parse(`${
data}`); // example:{ 'userId': 'liubao', 'message': '给你一个小爱心' }
let {
userId, message } = objMessage;
let count = 0; // 发送客户端数量
if (userId) {
clients.forEach(e => {
if (e['userId'] === userId) {
count++;
e['ws'].send(`${
message}`);
}
});
ws.send(`已发送userId为${
userId}的${
count}个客户端`);
} else {
ws.send(JSON.stringify({
error: '请发送指定userId的客户端' }));
}
} catch (err) {
ws.send(JSON.stringify({
error: err.message }));
}
});
ws.on('close', function close(event) {
console.log('关闭了');
});
});
const getParam = (url, param) => new URLSearchParams(new URL(url).search).get(param); // es6获取URL参数方法