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

时间:2018-06-15 13:38:27

标签: javascript web websocket ping pong

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

我想知道一些事情:

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

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

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

注意:抱歉我的英文。

4 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:4)

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

但是,如果服务器继续终止套接字连接,并且您无法控制它,则客户端可能会在一段时间内向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();

我强烈建议您尝试解决服务器端发生的问题,而不是尝试在客户端上解决问题。

答案 2 :(得分:1)

Mozilla为ping / pong记录了专用约定。

  

在握手之后的任何时候,客户端或服务器都可以   选择向对方发送ping。收到ping后,   接收者必须尽快寄回乒乓球。您可以使用   例如,这可以确保客户端仍处于连接状态。

     

乒乓球只是常规帧,但它是控制帧。   Ping的操作码为0x9,Pong的操作码为0xA。当你   进行ping操作,并使用与有效载荷数据完全相同的有效载荷数据发回pong   ping(对于ping和pongs,最大有效载荷长度为125)。你可能   不用发ping球也能拿到Pong;如果忽略它   发生。

     

如果您有超过一次的ping操作,则有机会   发一个乒乓球,你只发一个乒乓球。

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

Sending websocket ping/pong frame from browser

上,从浏览器端找到有关ping / pong的更深入讨论。

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

答案 3 :(得分:0)

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