如何在JavaScript中实现对WebSocket连接的Ping / Pong请求?

Qwe*_*nse 6 javascript ping websocket pong web

我在javascript中使用websocket。但是一分钟后连接关闭。

我在想什么:

1- Websocket是否自然不会提供Ping / Pong消息以关闭连接?我认为必须。否则,websocket和TCP连接之间有什么区别?

2-如果必须发送ping / pong消息,如何发送ping消息?我该怎么办?WebSocket对象是否提供ping方法?还是应该将方法称为websocket.send(“ ping”)?我在javascipt中使用Naturally WebSocket对象。

3-服务器是否应使用Pong响应Ping请求?是否应该在服务器端单独实现?

注意:对不起,我的英语。

oun*_*uni 8

此时,心跳通常是在服务器端实现的:从客户端可以做的事情并不多。

但是,如果服务器不断终止您的套接字连接,而您无法控制它,则客户端可能会按时间间隔向 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();
Run Code Online (Sandbox Code Playgroud)

我强烈建议尝试理清服务器端发生的事情,而不是尝试在客户端上解决它。

  • 这不是乒乓球。一定有一些常规的方法可以让客户端发起乒乓球,对吧? (3认同)
  • @ChrisSchmitz 我等了两年才有人注意到,现在我的精神终于可以自由了~ (3认同)
  • https://github.com/websockets/ws#how-to-detect-and-close-broken-connections (2认同)
  • 我很欣赏改变后的野兽参考:) (2认同)
  • 如果您想定期确保客户端套接字仍然处于连接状态,那么从服务器端发起的 ping/pong 没有任何问题。ping/pong 的全部目的是检测损坏的管道,而不是保持连接处于活动状态。电池和无线电管理由操作系统处理,因此超出了此处的范围。然而,对于这个答案来说,这是一个相当粗略的解决方案,在某些情况下可能有效。如果每 60 秒断开一次连接,500 毫秒肯定有点过分了。 (2认同)

Pim*_*den 7

Mozilla 记录了一个专门的 ping/pong 约定。

握手后的任何时刻,客户端或服务器都可以选择向对方发送 ping。收到 ping 后,接收者必须尽快发回 pong。例如,您可以使用它来确保客户端仍然处于连接状态。

ping 或 pong 只是一个常规帧,但它是一个控制帧。Ping 的操作码为 0x9,pong 的操作码为 0xA。当您收到 ping 时,发回一个 pong,其负载数据与 ping 完全相同(对于 ping 和 pong,最大负载长度为 125)。您也可能在不发送 ping 的情况下获得了 pong;如果发生这种情况请忽略。

如果您在有机会发送 pong 之前获得了多个 ping,则您只能发送一个 pong。

请参阅: https: //developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#Pings_and_Pongs_The_Heartbeat_of_WebSockets

在此处查找有关浏览器端 ping/pong 的更多深入讨论:从浏览器发送 websocket ping/pong 帧

更具体地说,请阅读有关 ping/pong 的 Websocket RFC 6455


oun*_*uni 5

是的,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);
Run Code Online (Sandbox Code Playgroud)