JavaScriptでwebsocketを使用しています。しかし、接続は1分後に閉じます。
私は何か疑問に思っています:
1- Websocketは、接続を閉じないようにPing/Pongメッセージを自然に提供していませんか?しなければならないと思います。それ以外の場合、websocketとTCP接続の違いは何ですか?
2- ping/pongメッセージを送信する必要がある場合、pingメッセージはどのように送信されますか?何をする必要がありますか? WebSocketオブジェクトはpingメソッドを提供しますか?または、websocket.send( "ping")としてメソッドを呼び出す必要がありますか?私はjavasciptで自然にWebSocketオブジェクトを使用しています。
3-サーバーはPongでPing要求に応答する必要がありますか?これはサーバー側で個別に実装する必要がありますか?
注:私の英語は申し訳ありません。
この時点で、ハートビートは通常サーバー側で実装されます。クライアント側からできることはあまりありません。
ただし、サーバーがソケット接続を強制終了し続け、それを制御できない場合、クライアントは任意のデータを一定の間隔でwebsocketに送信できます。
let socket = null;
function connect_socket() {
socket = new WebSocket(ws_url);
socket.on("close", connect_socket); // <- rise from your Grave!
heartbeat();
}
function heartbeat() {
if (!socket) return;
if (socket.readyState !== 1) return;
socket.send("heartbeat");
setTimeout(heartbeat, 500);
}
connect_socket();
クライアントでそれを回避しようとするのではなく、サーバー側で何が起こっているかを整理することを強くお勧めします。
はい、websocketにはping/pongフレームがあります。サーバーがping要求を開始しているws
モジュールを使用した例を次に示します。
const http = require('http');
const ws = require('ws');
const server = http.createServer(function(req_stream_in, res_stream_out) {
// handle regular HTTP requests here
});
const webSocketServer = new ws.Server({
path: "/websocket",
server: server
});
const connected_clients = new Map();
webSocketServer.on('connection', function connection(ws_client_stream) {
// NOTE: only for demonstration, will cause collisions. Use a UUID or some other identifier that's actually unique.
const this_stream_id = Array.from(connected_clients.values()).length;
// Keep track of the stream, so that we can send all of them messages.
connected_clients.set(this_stream_id, ws_client_stream);
// Attach event handler to mark this client as alive when pinged.
ws_client_stream.is_alive = true;
ws_client_stream.on('pong', () => { ws_client_stream.is_alive = true; });
// When the stream is closed, clean up the stream reference.
ws_client_stream.on('close', function() {
connected_clients.delete(this_stream_id);
});
});
setInterval(function ping() {
Array.from(connected_clients.values()).forEach(function each(client_stream) {
if (!client_stream.is_alive) { client_stream.terminate(); return; }
client_stream.is_alive = false;
client_stream.ping();
});
}, 1000);
Mozillaは、ping/pong専用の規約を文書化しています。
ハンドシェイク後の任意の時点で、クライアントまたはサーバーのいずれかが、相手にpingを送信することを選択できます。 pingを受信すると、受信者はできるだけ早くポンを返送する必要があります。これを使用して、たとえば、クライアントがまだ接続されていることを確認できます。
PingまたはPongは単なる通常のフレームですが、制御フレームです。 Pingのオペコードは0x9で、pongのオペコードは0xAです。 pingを取得したら、pingとまったく同じペイロードデータでポンを送り返します(pingとポンの場合、最大ペイロード長は125です)。また、pingを送信せずにピンポンを取得する場合もあります。発生した場合はこれを無視してください。
ピンポンを送信する機会が得られる前に複数のpingを取得した場合は、1つのピンポンのみを送信します。
ブラウザ側からのping/pongについての詳細な議論は、ここにあります: ブラウザからのwebsocket ping/pongフレームの送信
より具体的には、Websocket RFC 6455 ping/pongについてお読みください。
Ouniのソリューションでは、heartbeat()は作動していませんでした。次のようなopen
イベントに入れたときに機能します。
let socket = null;
function connect_socket() {
socket = new WebSocket(ws_url);
socket.on("close", connect_socket); // <- rise from your Grave!
socket.on("open", heartbeat); // heartbeat when the socket is open
}
function heartbeat() {
if (!socket) return;
if (socket.readyState !== 1) return;
socket.send("heartbeat");
setTimeout(heartbeat, 500);
}
connect_socket();