如何在javascript 中实现Ping/Pong 的webSocket 连接请求?
How to implement Ping/Pong request for webSocket connection alive in javascript?
我在 javascript 中使用 websocket。但是连接在一分钟后关闭。
我想知道一些事情:
1- Websocket 不是自然地提供 Ping/Pong 消息来关闭连接吗?我认为它必须。否则websocket和TCP连接有什么区别?
2- 如果我必须发送 ping/pong 消息,ping 消息是如何发送的?我需要做什么? WebSocket 对象是否提供 ping 方法?或者我应该将方法称为 websocket.send("ping") 吗?我在 javascipt 中使用自然的 WebSocket 对象。
3- 服务器应该用 Pong 响应 Ping 请求吗?这应该在服务器端单独实现吗?
注意:对不起我的英语。
是的,websockets 中有 ping/pong 个帧。这是一个使用 ws
模块的示例,其中服务器正在发起 ping 请求:
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);
此时,心跳通常在服务器端实现:客户端无能为力。
但是,如果服务器不断终止您的套接字连接,而您无法控制它,则客户端有可能在一定时间间隔内向 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();
我强烈建议尝试弄清楚服务器端发生了什么,而不是尝试在客户端解决它。
在 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();
Mozilla 记录了 ping/pong 的专用约定。
At any point after the handshake, either the client or the server can
choose to send a ping to the other party. When the ping is received,
the recipient must send back a pong as soon as possible. You can use
this to make sure that the client is still connected, for example.
A ping or pong is just a regular frame, but it's a control frame.
Pings have an opcode of 0x9, and pongs have an opcode of 0xA. When you
get a ping, send back a pong with the exact same Payload Data as the
ping (for pings and pongs, the max payload length is 125). You might
also get a pong without ever sending a ping; ignore this if it
happens.
If you have gotten more than one ping before you get the chance to
send a pong, you only send one pong.
在此处从浏览器端找到关于 ping/pong 的更多深入讨论:Sending websocket ping/pong frame from browser
更具体地说,阅读有关 ping/pong 的 Websocket RFC 6455。
我在 javascript 中使用 websocket。但是连接在一分钟后关闭。
我想知道一些事情:
1- Websocket 不是自然地提供 Ping/Pong 消息来关闭连接吗?我认为它必须。否则websocket和TCP连接有什么区别?
2- 如果我必须发送 ping/pong 消息,ping 消息是如何发送的?我需要做什么? WebSocket 对象是否提供 ping 方法?或者我应该将方法称为 websocket.send("ping") 吗?我在 javascipt 中使用自然的 WebSocket 对象。
3- 服务器应该用 Pong 响应 Ping 请求吗?这应该在服务器端单独实现吗?
注意:对不起我的英语。
是的,websockets 中有 ping/pong 个帧。这是一个使用 ws
模块的示例,其中服务器正在发起 ping 请求:
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);
此时,心跳通常在服务器端实现:客户端无能为力。
但是,如果服务器不断终止您的套接字连接,而您无法控制它,则客户端有可能在一定时间间隔内向 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();
我强烈建议尝试弄清楚服务器端发生了什么,而不是尝试在客户端解决它。
在 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();
Mozilla 记录了 ping/pong 的专用约定。
At any point after the handshake, either the client or the server can choose to send a ping to the other party. When the ping is received, the recipient must send back a pong as soon as possible. You can use this to make sure that the client is still connected, for example.
A ping or pong is just a regular frame, but it's a control frame. Pings have an opcode of 0x9, and pongs have an opcode of 0xA. When you get a ping, send back a pong with the exact same Payload Data as the ping (for pings and pongs, the max payload length is 125). You might also get a pong without ever sending a ping; ignore this if it happens.
If you have gotten more than one ping before you get the chance to send a pong, you only send one pong.
在此处从浏览器端找到关于 ping/pong 的更多深入讨论:Sending websocket ping/pong frame from browser
更具体地说,阅读有关 ping/pong 的 Websocket RFC 6455。