javascript 如何在javascript中实现webSocket连接的Ping/Pong请求?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/50876766/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 09:19:00  来源:igfitidea点击:

How to implement Ping/Pong request for webSocket connection alive in javascript?

javascriptwebwebsocketpingpong

提问by Qwer Sense

I use websocket in javascript. But the connection close after one minute.

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

I am wondering somethings:

我想知道一些事情:

1- Is not Websocket naturaly providing with Ping/Pong messages not to close the connection? I think it have to. Otherwise what is the difference between websocket and TCP connection?

1- 不是 Websocket 自然地提供 Ping/Pong 消息来不关闭连接吗?我认为它必须。否则 websocket 和 TCP 连接有什么区别?

2- If I have to send the ping/pong messages, how is the ping message sent? What am I need to do? Is WebSocket object provide a ping method? Or should I call a method as websocket.send("ping") ? I am use naturaly WebSocket object in javascipt.

2- 如果我必须发送 ping/pong 消息,ping 消息是如何发送的?我需要做什么?WebSocket 对象是否提供 ping 方法?或者我应该调用一个方法作为 websocket.send("ping") ?我在 javascipt 中使用自然的 WebSocket 对象。

3- Should the server respond to Ping requests with Pong? Should this be implemented separately on the server side?

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

Note:Sorry for my english.

注意:对不起我的英语。

采纳答案by ouni

At this point in time, heartbeats are normally implemented on the server side: there's not much you can do from the client end.

此时,心跳通常是在服务器端实现的:从客户端您无能为力。

However, if the server keeps killing your socket connection, and you have no control over it, it is possible for the client to send arbitrary data to the websocket on an interval:

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

I strongly recommend trying to sort out what's happening on the server end, rather than trying to work around it on the client.

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

回答by ouni

Yes, there are ping/pong frames in websockets. Here is an example using the wsmodule, where the server is initiating the ping request:

是的,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);

回答by Pim Heijden

Mozilla documents a dedicated convention for ping/pong.

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。当收到 ping 时,接收者必须尽快发回一个 pong。例如,您可以使用它来确保客户端仍处于连接状态。

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

如果在有机会发送 pong 之前您已经收到了多个 ping,则您只发送了一个 pong。

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

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

Find more in depth discussion about ping/pong from the browser side here: Sending websocket ping/pong frame from browser

从浏览器端找到更多关于 ping/pong 的深入讨论:Sending websocket ping/pong frame from browser

More specifically, read the Websocket RFC 6455about ping/pong.

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

回答by upteryx

In ouni's solution, heartbeat() wasn't kicking in. It works when it's put in an openevent like this:

在 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();