170

I keep reading about ping/pong messages in websockets to keep the connection alive, but I'm not sure what they are. Is it a distinct frame type? (I don't see any methods on a javascript WebSocket object in chrome related to ping-pong). Or is it just a design pattern (e.g. I literally send "ping" or any other string to the server and have it respond). Is ping-pong at all related to continuation frames?

The reason I ask is I'm using a python framework that runs behind Mongrel2, so I'm wondering if there's a way to send Mongrel2 a specific ping/pong message that would tell it to keep the connection alive without my python app needing to worry about it. Analogous to a having a separate HTTP method for it, I guess. And I imagine a dedicated ping/pong message frame could be simpler (less load on server and network) than the string "ping", though that probably wouldn't matter too much.

EDIT: I just looked at RFC 6455 and it looks like Ping and Pong are definitely control frame types with their own opcodes. So how do I send a Ping frame from javascript in Chrome?

Community
  • 1
  • 1
danny
  • 10,103
  • 10
  • 50
  • 57
  • Just ping from the server. Everyone knows about the networking issue on non-standard ports, so they're starting to ping at regular short intervals. I guess you could ping a poorly written server, but it might not be too smart to do anything sensitive with them. –  Feb 10 '14 at 13:48
  • https://github.com/websockets/ws/issues/977 – firstpostcommenter Jun 01 '18 at 11:48
  • 1
    @user1382306 ping from server first will use mobile device battery use very fast. Ping from client can save device battery. – bronze man Jul 09 '18 at 02:52
  • 2
    @user1382306 Not quite everyone! What is the networking issue on non-standard ports? – HappyDog Aug 16 '18 at 22:23

4 Answers4

157

There is no Javascript API to send ping frames or receive pong frames. This is either supported by your browser, or not. There is also no API to enable, configure or detect whether the browser supports and is using ping/pong frames. There was discussion about creating a Javascript ping/pong API for this. There is a possibility that pings may be configurable/detectable in the future, but it is unlikely that Javascript will be able to directly send and receive ping/pong frames.

However, if you control both the client and server code, then you can easily add ping/pong support at a higher level. You will need some sort of message type header/metadata in your message if you don't have that already, but that's pretty simple. Unless you are planning on sending pings hundreds of times per second or have thousands of simultaneous clients, the overhead is going to be pretty minimal to do it yourself.

kanaka
  • 70,845
  • 23
  • 144
  • 140
  • 1
    Is it possible to programmatically create a binary frame which contains the "ping" frame? – Nahum Bazes Feb 09 '22 at 10:36
  • 1
    This is how the `ws` Websocket lib does it: https://github.com/websockets/ws/blob/8a7016dc2fe4d9d63c428c67588d7c1f33a72e5c/lib/sender.js#L209 – Daniel W. Feb 09 '22 at 11:41
10

Update: Although the answer is old, it's in google's top results. At any point after the handshake, either the client or the server can choose to send a ping to the other party

Ping is meant to be sent only from server to client, and browser should answer as soon as possible with Pong OpCode, automatically. So you have not to worry about that on higher level.

Although that not all browsers support standard as they suppose to, they might have some differences in implementing such mechanism, and it might even means there is no Pong response functionality. But personally I am using Ping / Pong, and never saw client that does not implement this type of OpCode and automatic response on low level client side implementation.

Kirill Gamazkov
  • 3,277
  • 1
  • 18
  • 22
moka
  • 22,846
  • 4
  • 51
  • 67
  • Interesting, it does make more sense for the server to initiate the calls. What webserver are you using? – danny May 16 '12 at 16:52
  • I am using own implementation of WebSockets protocol on .Net / Mono for my own fun. Sources can be found here https://github.com/Maksims/gh12-server – moka May 16 '12 at 17:45
  • 1
    In my testing, I definitely found common browsers that don't support ping/pong; can't remember which – Marc Gravell Jul 25 '12 at 09:19
  • 2
    I've been doing server and client side websocket development for over a year and I find it rather frustrating that the Javascript API isn’t able to send ping frames. It would be great to be able to ping my servers and use the RTT to redistribute load. This can be done from the server, but it makes more sense to have the client side capability as well. I can't think of an actual downside to a client side ping. – JSON Jan 18 '14 at 20:22
  • 1
    There is always some logic related to pings on server side, for example: timeouts, averaging of latency, etc. And that is why if server does send PING - is always better. As well server need to know roundtrip: from server to client and back. No from client to server one way, as it all about both ways. So that is why server should always make their PING query. As well responding in actual JS logic to your ping events - is actually better, as reflects latency with account of application response speed. – moka Jan 21 '14 at 17:20
  • 106
    Where have you read that ping is only from server to client ? The RFC says "An endpoint MAY send a Ping frame any time after the connection is established and before the connection is closed." – xryl669 Apr 15 '14 at 10:28
  • 1
    It is general practice and knowledge across multiplayer applications, and WebSockets are not an exception. As latency and round-trip information has important applications on server side. If client needs that information it can get it from server. But to prevent "cheating" with latency (there are many problems can be related to such cheating case) PING should be always performed from server and not client. You can look for articles and best practices for developing multiplayer applications, and you will find info regarding this there. There is no functionality to send PING OpCode from client. – moka Apr 15 '14 at 11:03
  • 10
    If you want the client to automatically detect a disconnected state (when no RST/FIN packets have been received, but the network has been disconnected), then you need to have the client initiate ping packets as well. – pschwamb May 30 '14 at 04:08
  • For the need of checking if client is still connected there is different technique exactly for that purpose, and is called "heartbeating". Do not use ping mechanics for detecting disconnect state. In fact browsers are smart enough to detect disconnect state in current implementation of WebSockets as they are on top of TCP, and TCP is persistent connection network protocol, so that will be notified if connection is interrupted. So no extra work is required for that. You might worked with Socket.IO - so remember that it is a totally different and "ugly" case.. – moka May 30 '14 at 19:35
  • 21
    TCP does not notify of disconnects when RST/FIN packets were not received. TCP only detects dropped connections when a sender attempts to send on a disconnected connection. Pings are used as heartbeats in many applications and it's a valid use. A dead connection will simply remain dead forever until the client tries to send. Therefore, with WebSockets on the browser, a custom ping (or heartbeat) message must be used to detect client disconnect on the client side. The server may be trying to ping, and detecting the client disconnect, but the client is not informed. Client pings are also fine. – DDS Jan 01 '15 at 08:13
  • 22
    In RFC 6455, The WebSocket Protocol, it explicitly states: "NOTE: A Ping frame may serve either as a keepalive or as a means to verify that the remote endpoint is still responsive." – DDS Jan 01 '15 at 08:17
  • 7
    It's possible that the server-only ping was a recommended practice when user-agents were frequently refreshed. But now many websites are designed as SPAs. In this environment it might be quite essential for the client application to regularly ping the server in order to ensure the connection has not been lost. – Zephyr was a Friend of Mine May 19 '16 at 10:08
  • 1
    I'd love to know if this server side only thing works in practice, can anyone confirm that the major browsers don't ever send pings? RFC6455 does not say this AFACS – teknopaul Sep 02 '17 at 12:21
  • 5
    Ping can be send by either Client or Server. https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#Pings_and_Pongs_The_Heartbeat_of_WebSockets – Piyush Katariya Nov 27 '17 at 11:52
  • 2
    So, I'm still a little confused... It doesn't appear that the browser does this on its own and there is no API. There doesn't seem to be a way to send anything but text via Websocket.prototype.send so I can't manipulate headers and such. I'm very close to just implementing my own solution sending "PING" and expecting "PONG" but I get the feeling that is not how it is supposed to be done. I **do** have control of both client and server. – John Carrell Mar 22 '18 at 17:10
  • 4
    How we can tell to a JS developers that we need a API to configure pingPong intervals? I don't want to manually send and receive ping pong messages, but under the hood this mechanism must be implemented. And I need only API to configure it. pingIntervals, timeouts. 2018 today, whats the shame. – nail Jun 05 '18 at 08:31
  • 3
    It is commonplace for clients to send KeepAlive PINGs, indeed many wss APIs now require PINGs every 60s or so and actively close connections where clients do not initiate the PING. What may have been "common knowledge" in 2012 no longer applies, nevertheless, your statement has always contradicted the wording of the RFC6455 https://tools.ietf.org/html/rfc6455#section-5.5.2 I suggest you remove the "Ping is meant to be sent only from server to client" bit. – Robino Apr 14 '20 at 16:31
  • 3
    Is this still the state of the world in mid-2021? We haven't agreed on a way to say "Hey are you still there?" using WebSockets? – jamis0n Aug 06 '21 at 15:25
  • @jamis0n sounds about right and all the added misinformation on SO to go around. Easier to just read the specs than any threads about websockets here. Every single one is littered with biased / inaccurate info. – TaDaa Aug 20 '21 at 04:11
  • 1
    @moka This answer is shameful. As other comments have noted, the answer contains contradicting information. Also, your claims in the comments are misleading. One of the inherent applications, and probably the most common use case of ping/pong after latency measuring, is to detect broken pipes. A "heartbeat" will only test one of the two duplex channels so is normally not enough. A ping/pong is essentially just a two way heartbeat anyway. The reason people use it as well as TCP layer detection is to get a more up to date signal. TCP timeout is typically 120 seconds which is often too slow. – Phil Sep 05 '22 at 22:12
  • In my practice in most situations it was waaay more beneficial if it was up to clients to do (or decide to stop) pinging, so that the given client (end user in many cases) could decide whether it was important to put an effort into maintaining the connection. For example if I have a browser window with a websocket based chat app in the background, I don't want to lose connection while I'm working in the other window. However if I'm on a mobile device and press power to put it into sleep, I usually don't want drain the battery, so the browser should stop pinging (or better ask me what to do). – morgwai Sep 02 '23 at 13:26
7

a possible solution in js

In case of the WebSocket server initiative disconnects the ws link after a few minutes there were no messages be sent between the server and client.

  1. the client end initiative sends a custom ping message, to keep alive by using the keepAlive function

  2. the server end will ignore the custom ping message and responds to a custom pong message

let timerId = 0; 

function keepAlive(timeout = 20000) { 
    if (webSocket.readyState == webSocket.OPEN) {  
        webSocket.send('');  
    }  
    timerId = setTimeout(keepAlive, timeout);  
}

function cancelKeepAlive() {  
    if (timerId) {  
        clearTimeout(timerId);  
    }  
}

xgqfrms
  • 10,077
  • 1
  • 69
  • 68
  • 2
    This code sends empty frames, not ping or pong frames. – Remember Monica Nov 28 '20 at 00:47
  • 1
    @RememberMonica Please read my description first, I know what's going on. – xgqfrms Nov 29 '20 at 12:07
  • This gave me light to a keep-alive function which in my case is notifying the server to renew reading deadline value on the websocket connection (btw I'm in golang server in my case). Though I had to make it more meaningful by simulating it to send a pong string. Thank you! from Tanzania. – Dilunga the Great Dec 16 '20 at 08:23
3

No.

I attempted to implement a ping. There doesn't seem to be any way I can force a browser WebSocket client to set any opcode other than 0x1 (string) and 0x2 (binary).

const socket = new WebSocket(url);
ping() {
    if (socket?.readyState !== WebSocket.OPEN) {
      return;
    }
    const buffer = new ArrayBuffer(7);
    const dataView = new DataView(buffer);
    dataView.setInt8(0, 0x89);
    dataView.setInt8(1, 0x00);
    dataView.setInt8(2, 0x48);
    dataView.setInt8(3, 0x65);
    dataView.setInt8(4, 0x6c);
    dataView.setInt8(5, 0x6c);
    dataView.setInt8(6, 0x6f);
    socket.send(buffer);
  }
socket.addEventListener('open', ping);

This code should send a final (0x8) ping frame (opcode 0x09) with body "hello", but the browser sends a final frame in binary (0x82) that has body "�hello" where � is the 0x89 data.

thesmart
  • 2,993
  • 2
  • 31
  • 34