Skip to content

Commit 31ff875

Browse files
feat: reverse the ping-pong mechanism
The ping packets will now be sent by the server, because the timers set in the browsers are not reliable enough. We suspect that a lot of timeout problems came from timers being delayed on the client-side. Breaking change: v3.x clients will not be able to connect anymore (they will send a ping packet and timeout while waiting for a pong packet). Related: https://github.com/socketio/engine.io/issues/312
1 parent 2ae2520 commit 31ff875

File tree

4 files changed

+39
-15
lines changed

4 files changed

+39
-15
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ A representation of a client. _Inherits from EventEmitter_.
321321
- `type`: packet type
322322
- `data`: packet data (if type is message)
323323
- `packetCreate`
324-
- Called before a socket sends a packet (`message`, `pong`)
324+
- Called before a socket sends a packet (`message`, `ping`)
325325
- **Arguments**
326326
- `type`: packet type
327327
- `data`: packet data (if type is message)

lib/socket.js

+33-9
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class Socket extends EventEmitter {
3030
this.checkIntervalTimer = null;
3131
this.upgradeTimeoutTimer = null;
3232
this.pingTimeoutTimer = null;
33+
this.pingIntervalTimer = null;
3334

3435
this.setTransport(transport);
3536
this.onOpen();
@@ -60,7 +61,7 @@ class Socket extends EventEmitter {
6061
}
6162

6263
this.emit("open");
63-
this.setPingTimeout();
64+
this.schedulePing();
6465
}
6566

6667
/**
@@ -77,12 +78,12 @@ class Socket extends EventEmitter {
7778

7879
// Reset ping timeout on any packet, incoming data is a good sign of
7980
// other side's liveness
80-
this.setPingTimeout();
81+
this.resetPingTimeout(this.server.pingInterval + this.server.pingTimeout);
8182

8283
switch (packet.type) {
83-
case "ping":
84-
debug("got ping");
85-
this.sendPacket("pong");
84+
case "pong":
85+
debug("got pong");
86+
this.schedulePing();
8687
this.emit("heartbeat");
8788
break;
8889

@@ -112,15 +113,34 @@ class Socket extends EventEmitter {
112113
}
113114

114115
/**
115-
* Sets and resets ping timeout timer based on client pings.
116+
* Pings client every `this.pingInterval` and expects response
117+
* within `this.pingTimeout` or closes connection.
116118
*
117119
* @api private
118120
*/
119-
setPingTimeout() {
121+
schedulePing() {
122+
clearTimeout(this.pingIntervalTimer);
123+
this.pingIntervalTimer = setTimeout(() => {
124+
debug(
125+
"writing ping packet - expecting pong within %sms",
126+
this.server.pingTimeout
127+
);
128+
this.sendPacket("ping");
129+
this.resetPingTimeout(this.server.pingTimeout);
130+
}, this.server.pingInterval);
131+
}
132+
133+
/**
134+
* Resets ping timeout.
135+
*
136+
* @api private
137+
*/
138+
resetPingTimeout(timeout) {
120139
clearTimeout(this.pingTimeoutTimer);
121140
this.pingTimeoutTimer = setTimeout(() => {
141+
if (this.readyState === "closed") return;
122142
this.onClose("ping timeout");
123-
}, this.server.pingInterval + this.server.pingTimeout);
143+
}, timeout);
124144
}
125145

126146
/**
@@ -191,7 +211,7 @@ class Socket extends EventEmitter {
191211
self.clearTransport();
192212
self.setTransport(transport);
193213
self.emit("upgrade", transport);
194-
self.setPingTimeout();
214+
self.schedulePing();
195215
self.flush();
196216
if (self.readyState === "closing") {
197217
transport.close(function() {
@@ -283,7 +303,11 @@ class Socket extends EventEmitter {
283303
onClose(reason, description) {
284304
if ("closed" !== this.readyState) {
285305
this.readyState = "closed";
306+
307+
// clear timers
308+
clearTimeout(this.pingIntervalTimer);
286309
clearTimeout(this.pingTimeoutTimer);
310+
287311
clearInterval(this.checkIntervalTimer);
288312
this.checkIntervalTimer = null;
289313
clearTimeout(this.upgradeTimeoutTimer);

package-lock.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/server.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1011,8 +1011,8 @@ describe("server", function() {
10111011

10121012
engine.on("connection", function(conn) {
10131013
conn.once("heartbeat", function() {
1014+
socket.onPacket = function() {};
10141015
setTimeout(function() {
1015-
socket.onPacket = function() {};
10161016
expect(clientCloseReason).to.be(null);
10171017
}, 150);
10181018
setTimeout(function() {
@@ -2396,15 +2396,15 @@ describe("server", function() {
23962396
});
23972397
});
23982398

2399-
it("should emit when receives ping", function(done) {
2399+
it("should emit when receives pong", function(done) {
24002400
var engine = listen({ allowUpgrades: false, pingInterval: 4 }, function(
24012401
port
24022402
) {
24032403
eioc("ws://localhost:%d".s(port));
24042404
engine.on("connection", function(conn) {
24052405
conn.on("packet", function(packet) {
24062406
conn.close();
2407-
expect(packet.type).to.be("ping");
2407+
expect(packet.type).to.be("pong");
24082408
done();
24092409
});
24102410
});
@@ -2435,7 +2435,7 @@ describe("server", function() {
24352435
engine.on("connection", function(conn) {
24362436
conn.on("packetCreate", function(packet) {
24372437
conn.close();
2438-
expect(packet.type).to.be("pong");
2438+
expect(packet.type).to.be("ping");
24392439
done();
24402440
});
24412441
});

0 commit comments

Comments
 (0)