How does one share a single WebSocket connection across multiple browser tabs?
I'm aware of multiple questions/posts suggesting SharedWorker. However, it is not a viable solution due to the poor adoption of SharedWorker (only 35% globally according to Can I use at the time of writing), not to mention it has been dropped in Safari.
I have implemented a working version using SerivceWorker, which has some SharedWorker's capability, to share a single connection across tabs. Unfortunately during testing I realized that ServiceWorker can be killed/stopped by the browser, especially when the devtool is not opened. I'm also aware of some workaround to prevent this behaviour, such as pinging the ServiceWorker periodically. I would like to ask whether there is a proper way to handle this.
Unfortunately is not a straightforward task. But because many browsers are limiting the number of connections to the same origin it is an issue I faced a few times.
Sharing a WebSocket
Assuming you are forced to share the connection and other options are not feasible, these are the possibilities:
SharedWorker (33.17% support). Allows you to share the connection as you already discovered.
BroadcastChannel (91.23% support). Allows you to communicate between tabs.
SessionStorage (97.25%). Allows you to communicate between tabs. This is a bit of a hack see but worked well for me.
The trick for 2 and 3 is that you will have only one tab holding the WS connection and sharing its usage with the other tabs through the communication channel. The trickiest part is when the "main" tab is closed; you will need to elect another tab to open the connection.
Please note that both 2 and 3 are subject to buffering delays and additional delays during the change of the "main" tab. SharedWorker also has its pitfalls. Thus none of the solutions are suitable for high-speed real-time applications (like a game). If you need a real-time solution or just one that is easier to implement go for the following option:
Unsollecitated option
If you just need to work around the connection limitation, this is a cheat that works flawlessly: create a domain like *.wss.example.com that points to the same server and then trick the browser by randomly generating the domain on each tab (something like 3af893.wss.example.com, a6a589.wss.example.com, ...). With this pattern, you can make unlimited connections. Just remember to setup solid CORS policies as this pattern exposes you to huge amounts of malicious traffic otherwise.
Despite implementing many of the above mentioned solutions, I ended using this one in production as it prooved to be more stable and reliable. This solution also works for Server Side Events (SSE).
Edit 1
Many of the mentioned options are discussed here Sharing websocket across browser tabs? as mentioned by Eskandar
Related
Why did Safari drop support for SharedWorker?
And are there any working polyfills using, for example, localStorage and StorageEvent as a communication port? (Yes, the shim would have to detect and recreate the master Worker)
Directly from one of the WebKit Engineers:
The implementation of Shared Web Workers was imposing undesirable
constraints on the engine. It never gained any adoption.
Source here
I can't find any polyfills for SharedWorker.
It seems that one can be created by implementing a StorageEvent based communication port across workers. The downside being that StorageEvents are not portable for WebWorkers, and you have to maintain state across each browser tab and know when to flick on/off each master worker.
From my understanding the answers here are correct, but it's also due to the lack of SharedWorker adoption by web developers (a chicken and egg type situation).
If you're in need of a polyfill, you can use the one I created. I couldn't find one for one of my projects, so I created this one, https://sharedworker.okikio.dev/.
Note: it doesn't handle cross tab communication, but you can use the CacheStorage API together with a ServiceWorker and MessageChannel or use IndexedDB and ServiceWorker (from #jakearchibald on Twitter) to create a similar effect
Also: I should mention that Safari is working on supporting the BroadcastChannel API, which would cover the cross tab communication aspect, it's currently available in the Webkit Technology Preview
Since safari default's behaviour on cookies is preventing third-party cookies on tracking.
If safari allows us to use SharedWorker, developer(google or tracking company) can use it to access identify between different window tab.
That's the reason why safari drop the SharedWorker, interestingly, it support WebWorker but not SharedWorker.
It's my guess, not the official reason.
I'm trying to make a site as responsive as possible for phone users, and that means removing several bandwidth-hungry features. In particular, I'd like to load an external font if the user is on wifi but not on 3g/4g.
A pretty good proxy for this is 'phone or tablet', with tablets usually being the cutoff for 'good connection'. This kinda works, but there are 3g/4g tablets, and there are phones on wifi, so it's not perfect.
I don't think it's possible to get this any better, but perhaps stackoverflow's collective wisdom has discovered a way. Is this detectable?
Rather than focusing on mobile or not, just do a bandwidth test. The only way to really be sure is measure the time to download a file to their device.
Try the accepted answer here: How to detect internet speed in Javascript?
You can try the solution suggested in this answer, that is to use navigator.connection.type. However, this is definitely non-standard and it seems to be limited to Android devices only. Also, see the MDN entry, which mentions a metered property on the same navigator.connection object - this may also be useful.
For the best coverage: var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
The only way to do this I know of, which has it's own problem, is to do a reverse lookup on the IP address of the request at the time of the request (on the web server) and see if it's from a Wireless Carrier. The two problems with this are; that I don't know if mobile devices use a different network than say wired networks (Version Wireless vs Version Fios), and the other problem is employees of those companies who may actually be wired will appear wireless.
You could try doing a network probe for very common local addresses (only reachable over Wifi), such as 192.168.1.100 and friends. Here's how:
Create an img element with an onError handler.
Set the src property to the address you want to "ping"
If you get an error, then you know the address does not exist
No error means the address exists
I initially read about this technique in Ajax Security (great book).
JavaScript does not provide any hooks into network-level connection types. The best you can do is time the download of a known test file and decide based on that.
If that fails, just ask the user if they prefer the high/low bandwidth setting.
The title basically says it all. I'm aware this can't be done using traditional means. I'm not aware of any way to do it using Web Sockets, though I've never built anything more than toy apps with them.
It is fine if the solution is browser-specific (even on the client-side; i.e. peer-to-peer communication would also be awesome). For instance, is there any way to accomplish this using Chrome's NaCl?
Furthermore, if this isn't possible now, is there any fleshed-out specification for how it will work in the future? For instance, Chromium-based browsers are experimenting with a "P2P Javascript API" which appears to be currently entirely undocumented.
Here's the HTML5 spec on it:
http://www.whatwg.org/specs/web-apps/current-work/multipage/video-conferencing-and-peer-to-peer-communication.html#peer-to-peer-connections, though its status is unclear.
Sorry if this question is a bit haphazard; I'm basically interested in the current status of all in-browser APIs that could be used for p2p communication.
Edit: I'm not interested in Flash p2p. I'm aware it can be done, and is definitely a solution to current p2p problems, however I'm interested in new technology.
Update May 2012: For those still looking at this, the peerconnection API is slowly making its way into browsers. It is now experimentally in Chrome, along with the rest of the WebRTC API. You can check out the documentation and spec here.
There's Opera Unite but I'm not aware of any cross-browser standardization effort based on that. I think by default it proxies through Opera's servers for DNS, but you can set it up for direct connections.
Are there any plans for a Websockets listen function?
Allowing peer to peer applications in the browser could be revolutionary.
I found this answer: Will HTML5 allow web apps to make peer-to-peer HTTP connections? but it is rather old. I think the specification it refers to (the Connection api) has now been replaced with Websockets, which does not mention any listen facility.
The WebSockets API does not provide a way to listen for connections; it is client only.
You might be interested in Opera Unite.
Update:
Also check out pusherapp. It's a WebSockets service online. They charge for over 5 clients, but it's super simple to setup and use. Depending on what your p2p application requirements are, it might suffice.
Old question, but I was wondering the same thing, and came across peer-server, which might be worth having a look at. It uses WebRTC, and looks like it does what you're thinking:
https://github.com/PeerServer/peer-server
Tangentially related to your question, but you did say "p2p in the browser", so..
The Flash player has p2p APIs that allow direct connection with other peers (typically other browsers) over UDP.
The APIs are geared toward using those connections for voice/video streaming, but it seems possible to use them for generic message passing as well.
The tricky point of course is "how do peers find each others?". Currently, Adobe offers a free/beta service to do that, called Cirrus (formerly Stratus). It's also possible to buy Flash Media servers from Adobe to do the same (which also provide TCP server-based fallbacks for folks that are behind UDP-unfriendly firewalls.) Presumably, open-source alternatives like Red5 will have support for it too at some point.
If you are not looking for a generic browser solution, for non secure and limited connections you may use a Google Chrome extension to do the job:
Web Server for Chrome
https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb
I'm not talking about browser exploits. I'm talking about real applications used in real companies, like Ijji and Nexon.
Basically, from their websites you can click a "Start Game" button, which will launch an executable located at c:\ijji\english or c\nexon[gamename] respectively. These applications are real desktop applications, meaning that they can take advantage of the filesystem, direct3d, and OS [in the form of executing other applications]. The applications can also be launched through command line [as opposed to going to the game host's website].
I figured this would be possible if the application created an ActiveX object to call for the creation of a new process. However, the websites are able to launch applications from multiple browsers other than Internet Explorer, including chrome, which, to my knowledge, does not implement ActiveX.
Obviously the people developing these applications use their own means to do this.
From looking at the services list as well as currently running applications list, I have no indication that they're running something like "gameLaunchingServer.exe" which listens to some obscure port for an incoming connection [to be accessed using iframe - HTTP Protocol] and responds by launching an application...
I'm stumped, and this is sort of stuck in my mind. Obviously, they're not using some random browser exploit, otherwise people at http://www.[insertMaliciousWebsiteHere].com would have jumped on the opportunity already to install random crap. Regardless, it seems pretty cool, and I wanted to know how it worked.
Just curious, hehe.
I believe what they're doing is setting up their own protocol handler on install - when a browser is asked to access an address with a protocol that it doesn't know how to handle (for instance, a steam:// address), it looks at all the installed protocol handlers to find a match.
So you can register your application as a myApplication:// protocol handler, and then your web page can link to a myApplication:// address and launch your application.
I didn't quite find the button you are talking about, but I'm thinking it works only after you installed the application once, isn't it?
In that case, the application probably created its own protocol, just as skype, msn and a bunch of clients.
Having a protocol is the easiest way (and very easy indeed to implement - a simple registry key).
Another way which is used is an extension or plugin.
I thought they were run through plug-ins or like applets.
For example, MS SilverLight