1. Binary data.
Currently, sockjs doesn't do binary data. Fortunately, you can
just encode numbers as unicode and send it that way.
(I'm quite proud about that :P)
But this is inefficient - encoding 8 bits can take up to 6 bytes
(\uxxxx form for some chars) and usually 2 bytes (for utf-8 encoding).
I'm thinking that we can do better by trying to utilize
ISO-8859-1 encoding instead of UTF-8 for http based transports
(xhr/jsonp and others). Of course some native websockets
implementations support binary data out of the box.
2. Support command line clients for SockJS.
Currently, SockJS has a small bit of framing on top of websockets
protocol. That makes creating a standalone command-line
SockJS client difficult - it must understand SockJS framing.
As opposed to current websockets url:
/prefix/server_id/session_id/websocket
i'm thinking of creating a new websockets url, that will expose
websockets without any additional framing, for example:
/prefix/websocket
That would make it easier to connect to sockjs from other
environments than browsers.
3. Faster fallback mechanism
Currently, when websockets (or other transports) aren't working, SockJS
usually waits for a timeout to occur (this is oversimplification, if websockets
actively _fail_, the fallback will happen much faster).
We can get rid of the hardcoded timeout (5 seconds now) in favor of
a timeout related to estimated RTT (round trip time) between a server
and a client. In the end - why wait 5 seconds if we know that the server
should respond in under 100 ms?
In some rare circumstances, from the server point of view, we could end
up in having two sockjs sessions opened (due to an inevitable race condition).
But I think this is a cost worth taking.
(Doing this may require significant changes to the fallback-choosing mechanism).
What do you think?
Are there any other things that SockJS could improve on?
Marek
I was thinking of base64 which is fast, trivially coded and inflates
to only a 1/3 of initial message.
> 2. Support command line clients for SockJS.
>
> Currently, SockJS has a small bit of framing on top of websockets
> protocol. That makes creating a standalone command-line
> SockJS client difficult - it must understand SockJS framing.
>
> As opposed to current websockets url:
> /prefix/server_id/session_id/websocket
> i'm thinking of creating a new websockets url, that will expose
> websockets without any additional framing, for example:
> /prefix/websocket
>
> That would make it easier to connect to sockjs from other
> environments than browsers.
einaros has been working on https://github.com/einaros/ws -- i believe
we should look at that and may be adopt something
> 3. Faster fallback mechanism
>
> Currently, when websockets (or other transports) aren't working, SockJS
> usually waits for a timeout to occur (this is oversimplification, if websockets
> actively _fail_, the fallback will happen much faster).
>
> We can get rid of the hardcoded timeout (5 seconds now) in favor of
> a timeout related to estimated RTT (round trip time) between a server
> and a client. In the end - why wait 5 seconds if we know that the server
> should respond in under 100 ms?
>
> In some rare circumstances, from the server point of view, we could end
> up in having two sockjs sessions opened (due to an inevitable race condition).
> But I think this is a cost worth taking.
>
> (Doing this may require significant changes to the fallback-choosing mechanism).
>
I'd explore the possibility to upgrade instead of fallback -- i.e.
first connect with bullet-proof jsonp and then "may be reconnect"
using higher protocols, at idle
> What do you think?
>
> Are there any other things that SockJS could improve on?
>
I'd vote pro sheduling exploring another encoding/decoding techniques
(still need some insight how to cope with escaping of JSON in Lua).
--Vladimir
I'd like to share few ideas about improving various low-level aspects
of SockJS. Some are quite ambitious. Feedback welcome.
1. Binary data.
2. Support command line clients for SockJS.
As opposed to current websockets url:
/prefix/server_id/session_id/websocket
i'm thinking of creating a new websockets url, that will expose
websockets without any additional framing, for example:
/prefix/websocket
einaros has been working on https://github.com/einaros/ws -- i believewe should look at that and may be adopt something
> 3. Faster fallback mechanism
I'd explore the possibility to upgrade instead of fallback -- i.e.
first connect with bullet-proof jsonp and then "may be reconnect"
using higher protocols, at idle
I wouldn't be so definite. Please, read its readme -- it's both server
_and client_, which is the point of the question.
>>
>> > 3. Faster fallback mechanism
>> I'd explore the possibility to upgrade instead of fallback -- i.e.
>> first connect with bullet-proof jsonp and then "may be reconnect"
>> using higher protocols, at idle
>
> I am, personally, against this change. It will complicate things and won't
> solve the problem.
>
One should always be capable of connecting via jsonp, providing stack
is ok. This will allow to establish connection as quick as possible
which is quite a killer feature of the most nowdays apps.
> User will still have to wait and he won't receive or send any data during
> upgrade phase because of possible race conditions.
That's why I used the word 'at idle'.
> Keeping that in mind, it
> is better to wait in the beginning and use best available transport instead
> of connecting with something and then block _active_ connection while trying
> to upgrade.
Upgrade should take place between polling cycles, hence with minimal penalty.
>
> Forgot to mention - SockJS should put a cookie with last established
> transport to avoid probing on next run.
>
Noway, man, it's way naive. It will as well remember jsonp.
Worth mentioning, that all these points have been investigated by
socket.io team, answers to be read in engine.io goals. No need to
repeat the same explorations.
> Serge.
--Vladimir
I wouldn't be so definite. Please, read its readme -- it's both server_and client_, which is the point of the question.
> User will still have to wait and he won't receive or send any data duringThat's why I used the word 'at idle'.
> upgrade phase because of possible race conditions.
> Keeping that in mind, itUpgrade should take place between polling cycles, hence with minimal penalty.
> is better to wait in the beginning and use best available transport instead
> of connecting with something and then block _active_ connection while trying
> to upgrade.
> Forgot to mention - SockJS should put a cookie with last establishedNoway, man, it's way naive. It will as well remember jsonp.
> transport to avoid probing on next run.
Yes. I was responding to "2. Support command line clients for SockJS."
> Please define "idle". Only client can make decision when to switch to
> another transport. So, if server has some data to send, client won't be able
> to receive once upgrade completed, even though connection is established.
>
> In SockJS (for example), it might take up to 5s to decide that transport
> timed out. In socket.io, with default settings, it will take up to 8 seconds
> to fail and switch back to jsonp transport.
>
> So, from users perspective, there's no difference if client will wait for 5s
> before connecting or waiting data for 5 seconds after connecting. But this
> feature would require SockJS (or engine.io) developers to write code and
> test it.
>
> Again, what's the point?
>
>>
>> > Keeping that in mind, it
>> > is better to wait in the beginning and use best available transport
>> > instead
>> > of connecting with something and then block _active_ connection while
>> > trying
>> > to upgrade.
>> Upgrade should take place between polling cycles, hence with minimal
>> penalty.
>
> Right, and it will block any activity for established connection for
> duration of the upgrade.
>
Upgrade should be conditional. Conditions should be under the control.
This would provide for tunability.
Noone said upgrade must be attempted nomatter the conditions are.
>> > Forgot to mention - SockJS should put a cookie with last established
>> > transport to avoid probing on next run.
>> Noway, man, it's way naive. It will as well remember jsonp.
>
> Ahem, if client decided that best available transport is xhr-streaming, why
> would you want user to probe for websockets again on next page load?
>
Client is app-level. Let's stay library. You can use whatever to pin
the transport but that's not sockjs's business, i presume.
>
> One again, my personal opinion, doing transport upgrade won't solve problem
> it is supposed to solve.
>
> Serge.
It's worth testing, as it's in principle makes connection more
flexible hence robust.
also please look at https://github.com/sockjs/sockjs-node/issues/35
--Vladimir
Wow. So how many concurrent connections were you able to squeeze out of SockJS?
Impressive :)
No, I don't think of replacing /echo/x/x/websocket url. I'm just
thinking of adding
a new one /echo/websocket, that will be without any custom sockjs framing.
No JSON encoding, no heartbeats, no close frames. Pure websockets.
The point is to enable you to create stress test that actually sends/receives
data without making it custom for SockJS (and just keep it as a
generic websockets
stress test). Does it make sense?
Some people want to connect to SockJS from, for example node, thus the
custom SockJS framing and heartbeats aren't necessary.
Marek
Good idea. I need to benchmark it.
>> 2. Support command line clients for SockJS.
>>
>> Currently, SockJS has a small bit of framing on top of websockets
>> protocol. That makes creating a standalone command-line
>> SockJS client difficult - it must understand SockJS framing.
>>
>> As opposed to current websockets url:
>> /prefix/server_id/session_id/websocket
>> i'm thinking of creating a new websockets url, that will expose
>> websockets without any additional framing, for example:
>> /prefix/websocket
>>
>> That would make it easier to connect to sockjs from other
>> environments than browsers.
>
> einaros has been working on https://github.com/einaros/ws -- i believe
> we should look at that and may be adopt something
That's a different story, but good to know. I was thinking about getting
rid of current (custom) websockets server in sockjs-node and
maybe replacing it with:
https://github.com/jcoglan/faye-websocket-node
but, your suggestion
https://github.com/einaros/ws
also looks interesting. I'll evaluate.
Marek
Maybe no heartbeats at all?
It's intended to be more local-network server-to-server thing,
so heartbeats may not be neccessary.
Or maybe we should send ping/pong sometimes.
Not a big deal IMO.
Marek
Yep, that's the idea! The same API no matter what happens on the wire.
Base64 sounds like an option worth exploring.
Marek
Two issues emerged:
1) SockJS should remember last working transports
I personally won't use cookie but window.localstorage, but it's a detail.
The big question, is how long to keep the data for. If we can be sure
that the computer wasn't moved (ie: network conditions didn't change much),
we can trust previously selected cookie.
On the other hand, on a laptop the network may change every
time I open the lid.
Maybe Sockjs-server should return a client IP (or hash of it),
which could be used as key to find the cookie/localStorage
with previously working transport?
Or maybe we should just regularry clean up the cookie/localStorage
(every 10 minutes?).
2) Upgrade of protocols vs downgrande.
SockJS currently does "downgrade". ie: we start with good transports
(native websockets) and when that doesn't work, we look for another
one (worse), and so on.
I don't really understand the "upgrade" idea, I can't see the benefits.
It looks that all it does is delays the inevitable - waiting for a timeout
in a pessimistic case. It makes sense for flash-fallback preloading though.
Marek
On Dec 12, 10:18 pm, Sergey Koval <serge.ko...@gmail.com> wrote:
> Socket.io is doing it (though, it is possible to turn it off) and it really
> speeds up connection on page refresh. If cookies are disabled, so be it -
> it'll just try to find best transport again.
>
> But thanks for the article, it is interesting read.
>
> Serge.
>
Interesting. I'm afraid of users behind misbehaving proxies or firewalls.
It's quite bad when on every request user needs to wait for a websocket
timeout to get downgraded to xhr or jsonp.
I'm thinking of implementing it as a preference. ie: if previous
connection to ws failed, and xhr succeeded, let's this time start
from xhr and try ws later.
Ie: push previously working transport to the top of the transports
queue.
Would that work better?
Marek
And that's one of the reasons why engine.io is starting with a "upgrade" protocol insteadof a "fallback / downgrade" protocol.