Sending websocket ping/pong frame from browser
Asked Answered
Z

4

184

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?

Zoan answered 14/5, 2012 at 14:30 Comment(4)
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.Alpenglow
github.com/websockets/ws/issues/977Marsiella
@Alpenglow ping from server first will use mobile device battery use very fast. Ping from client can save device battery.Cryan
@Alpenglow Not quite everyone! What is the networking issue on non-standard ports?Dashboard
O
164

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.

Ocana answered 14/5, 2012 at 15:41 Comment(2)
Is it possible to programmatically create a binary frame which contains the "ping" frame?Pelisse
This is how the ws Websocket lib does it: github.com/websockets/ws/blob/…Frailty
A
11

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.

Ask answered 15/5, 2012 at 9:40 Comment(22)
Interesting, it does make more sense for the server to initiate the calls. What webserver are you using?Zoan
I am using own implementation of WebSockets protocol on .Net / Mono for my own fun. Sources can be found here github.com/Maksims/gh12-serverAsk
In my testing, I definitely found common browsers that don't support ping/pong; can't remember whichScopp
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.Pallbearer
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.Ask
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."Orleanist
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.Ask
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.Polyploid
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..Ask
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.Implosion
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."Implosion
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.Taurus
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 AFACSDacoit
Ping can be send by either Client or Server. developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/…Michael
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.Vestal
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.Amygdala
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 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.Flashy
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?Regalia
@Regalia 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.Pondicherry
@Ask 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.Maraschino
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).Muncy
This is exactly why browsers hide the ping method from developers. This is all done for you and you don't need to worry about it. Putting your phone to sleep will likely pause js execution anyway and so ws may timeout. When you build a chat app, it is very important you can recover your session on a new websocket when your client auto reconnects.Maraschino
A
7

An alternative JavaScript solution that sends an empty data frame, rather than a ping frame:

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);  
    }  
}

Army answered 3/11, 2020 at 7:51 Comment(4)
This code sends empty frames, not ping or pong frames.Larock
@RememberMonica Please read my description first, I know what's going on.Army
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.Overcasting
@Army Your description is still wrong, but this solution should work. Your code sends regular keepalive messages to keep the websocket alive. They are not pings. The server can ignore the keepalive message because it does not need to do anything. There is no custom pong message. The server and client both continue to react to underlying ws ping/pong mechanism that detects broken pipes.Maraschino
W
5

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.

Woolf answered 20/4, 2023 at 17:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.