Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Protocol version negotiation #21

Closed
kohtala opened this issue Dec 14, 2020 · 9 comments
Closed

Protocol version negotiation #21

kohtala opened this issue Dec 14, 2020 · 9 comments

Comments

@kohtala
Copy link

kohtala commented Dec 14, 2020

If I upgrade client to version 3, it will fail to connect to a group of servers that I am unable to upgrade at the same time. If I upgrade server, the clients that I am unable to upgrade at the same time will fail.

I use Socket.IO between many different clients and servers. I can not upgrade everything at the same time, because I do not have all under my control and they have maintenance breaks at different times over many months.

Thus I have clients that need to be able to talk to many different versions of servers (and I have servers that are connected to by clients of different versions).

This needs protocol version discovery and use of common version supported by both ends. Should be possible at least over two consecutive versions, or what ever span of versions is needed to cover possibly a maintenance period of a year.

Could be implemented for example by client sending the version he is using for the initial request. If server does not support it, report back with versions it supports for the client to try again.

@IlyaDiallo
Copy link

Exact same problem, and I suspect it's quite common.

@darrachequesne
Copy link
Member

First, thanks for raising this issue!

My only concern is about the bundle size of the client, if we add the negotiation logic.

I'd rather have the server handle both versions, a bit like the allowHTTP1: true option of the Node.js HTTP/2 server.

Is there any issue with the solution suggested in the migration guide here?

// npm i socket.io@2 socket.io-next@npm:socket.io@3
// or yarn add socket.io@2 socket.io-next@npm:socket.io@3
const httpServer = require("http").createServer();

const io = require("socket.io")(httpServer);
const ioNext = require("socket.io-next")(httpServer, {
  path: "/socket.io-next/"
});

const onConnection = (socket) => { ... }

io.on("connection", onConnection);
ioNext.on("connection", onConnection);

@IlyaDiallo
Copy link

IlyaDiallo commented Dec 17, 2020

My only concern is about the bundle size of the client, if we add the negotiation logic.

About ~2kB every 100 lines of code, is that really a concern ...? I'd think that the main concern would be the effort to write/test the logic...
Of course if the server handles both versions, the problem is solved (first upgrade all servers, then the clients over time).

@kohtala
Copy link
Author

kohtala commented Dec 18, 2020

Thanks. I and a colleague both had looked at the migration document. It seems that since most of the migration was something we did not need, we must have lost hope and failed to notice that the end was significant. Perhaps it would help if the TL;DR in beginning have a hint that while protocols are incompatible, instructions to run both at the same time are provided. Give the reader some hope to carry on till the end of the document.

We ended in about the same solution. We must since there is no protocol negotiation now.

Like @IlyaDiallo commented, we plan to have different versions at the server.

We also have clients where the size is of no concern and they could support many versions (without any obligation to do so), and since same client may need to support servers of many versions it would be useful to do so. If the version it told on initial connect was the highest version it supported, the server could respond with that or a lower version (like TLS for example). Or report all versions it supports, if we think client might skip versions. If client does not support the lower version, it knows not to try to parse the answer any further and can give meaningful error to user. This saves the client from trying many endpoints trying to find a common version.

@IlyaDiallo
Copy link

Perhaps it would help if the TL;DR in beginning have a hint that while protocols are incompatible, instructions to run both at the same time are provided. Give the reader some hope to carry on till the end of the document.

Yes - in fact I fell into the same trap, I didn't see the solution until @darrachequesne pointed to it in his response. Even better than a hint, adding a link to the solution in the TL;DR. As is it the TL;DR is more harmful than helpful IMO.

@IlyaDiallo
Copy link

Thinking more about the two-servers workaround, beside the doc discussion (fair point but minor), I was wondering about a bigger issue: if two server instances are running, would not the two groups of clients connected to each server be isolated from each other ...?

@kohtala
Copy link
Author

kohtala commented Dec 29, 2020

I planned to just make the application call both libraries for events. Or rather I add in the newest version of interface calls to the older version. There are also ways to scale horizontally by using a pub-sub message broker. Not sure if that would also allow passing messages between versions or if it would be another problem to solve as I've not really thought about that in more detail. We do not have any need for that in sight.

darrachequesne added a commit to socketio/engine.io that referenced this issue Jan 14, 2021
In order to ease the migration to Socket.IO v3, the Engine.IO server
can now communicate with v3.x clients.

```js
const eioServer = require("engine.io")(httpServer, {
  allowEIO3: true // false by default
});
```

If `allowEIO3` is false, the v3.x clients will now receive an HTTP 400
response ("Unsupported protocol version").

Note: the code of the v3 parser has been imported from [1] and
browser-related dependencies were removed.

[1]: https://github.com/socketio/engine.io-parser/tree/2.2.1

Related:

- socketio/engine.io-protocol#35
- socketio/socket.io-protocol#21
@darrachequesne
Copy link
Member

Starting from version 3.1.0, the Socket.IO server is now able to communicate with v2 clients:

const io = require("socket.io")({
  allowEIO3: true // false by default
});

@darrachequesne
Copy link
Member

I think we can close this now. Please reopen if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants