Receiving messages without port forwarding - javascript

I want a server to be able to send a client a message at any time. There may be no messages for several days, yet if one is sent, I want it to be received almost immediately (ideally within 1 second or less). How would I go about this without setting the client up as a server and using port forwarding?
An example of this would be push notifications on a mobile device. Apple can send a push notification to an iPhone almost instantly. However, the iPhone isn't acting as a server. Furthermore, the iPhone may be moving from network to network, and the networks aren't forwarding any ports to the iPhone. How does this work? Assuming there's some sort of persistent connection, how does the solution scale to hundreds of millions of devices connected at the same time?
This question doesn't depend on a particular language. I'm currently working in JS. I'm looking mostly for a conceptual answer, but feel free to answer it in the context of any language if that helps.

Remember that, once a network connection has been established, data can flow over it in either direction. There is no requirement that a peer be on the "receiving" end of a connection to receive data!
In the presence of a non-cellular network*, iPhone push notifications work by having the device connect to an Apple notification server, then wait to receive data from it. No port forwarding is necessary, as this is an outbound connection from the device. If the connection is lost, the device will reconnect to the server and "check in" to see if it missed anything.
*: If the device only has a cellular connection available, making it infeasible to keep a network connection open at all times, it may rely on notifications through the cellular network itself, kind of like SMS. But that's kind of a separate thing altogether.

Related

Socket.io clients seem to connect to different sockets on the same server

Hi I'm running a standard (example) socket.io chatroom, but I'm running into a problem I'm not sure how to debug.
The chatroom seems to functioning normally, clients can broadcast their messages, but occasionally on connection it is as if they are alone in the chatroom when they are not -- other clients don't see their presence or messages. It frequently happens when clients are not joining the socket around the same time.
It is as if they've connected to an entirely different socket.
I think it might be something to do with cookies and sessions. If the clients clear their sessions they are reunited in the chat.
Perhaps on (or before) connection I could clear session data? How?
There is no requirement for a chat server that clients connect on the same IP and port. Typically, there is a requirement that they connect to the same server, which must maintain a list of client connections to enable chat between them.
Chat works like this:
Server sets up a ServerSocket to accept connections. Clients connect, and these connections are stored on the Server in an array, object or some other form. When the server gets a message event from one of the clients, this message is then broadcast to all the other clients.
Thus, if you have one client who is not receiving any messages and appears to be in an empty room, the issue is likely that they are somehow not part of the same collection of connected clients, part of the same chat app, or not connected at all.
Okay I think I figured it out, I was right and wrong.
I think the clients were connecting to 'entirely different sockets' but it had nothing much to do with cookies and sessions:
I discovered (due to some other really weird bugs) by a study of running processes that somehow an old version of the socket.io server script was clinging to life in the background for some time. I expect clients were connecting to one of the two io server scripts randomly: not good. Working in a sense, but in separate worlds.
Killing those rogue processes seems to have fixed a lot of stuff.

Socket.io - remove jitter?

I have not been able to get an answer to this anywhere online. I want to remove possible jitter from my nodejs server. I am using socket.io to create connections to node.
If a user goes to a specific part of my website, a connection is started. However, if the user refreshes the site too quickly and often, the connection is created very frequently, and issues arise with my server.
While I realized it's possible this could be solved a couple different ways, I am hoping a server solution is out there. Meaning, whenever a user connects, make sure the user is connected for at least 5 seconds. Then move on. Otherwise, disconnect the user. Thanks for any insight!
First off a little background. With a default configuration, when a socket.io connection starts, it first does 2-5 http connections and then once it has established the "logical" connection, it tries to establish a connection using the webSocket transport. If that is successful, then it keeps that webSocket connection as a long lasting connection and sends socket.io packets over it.
If the client refreshes in the middle of the transition to a webSocket connection, it creates a period of unknown state on the server where the server isn't sure if the user is just still in the middle of the transition to a lasting webSocket connection, if the user is gone entirely already, if the user is having some sort of connection issues or if the user is doing some refresh thing. You can easily end up with a situation where the server thinks there are multiple connections all from the same user in the process of being confirmed. It can be a bit messy if your server is sensitive to that kind of thing.
The quickest thing you can do is to force the connection process to go immediately to the webSocket transport. You can do that in the client by adding an options to your connection code:
let socket = io(yourURL, {transports: ["websocket"]});
You can also configure the server to only accept webSocket connections if you're try to protect against any other types of connections besides just from your own web pages.
This will then go through the usual webSocket connection which starts with a single http request that is then "upgraded" to the webSocket protocol. Once connection, one socket. The server will know right away, either the user is or isn't connected. And, once they've switched over to the webSocket protocol, the server will known immediately if the user hits refresh because the browser will close the webSocket immediately.
The "start with http first" feature in socket.io is largely present because in the early days of webSockets, there were some browsers that didn't yet support them and some network infrastructure (like corporate proxies) that didn't always support webSocket connections. The browser issue is completely gone now. All browsers in use support webSocket connections. I don't personally have any data on the corporate proxies issues, but I don't ever hear about any issues with people using webSockets these days so I don't think that's much of an issue any more either.
So, the above change will get you a quick, confirmed connection and get rid of the confusion around whether a user is or isn't connected early in the connection process.
Now, if you still have users who are messing things up by rapid refresh, you probably need to just implement some protection on your server for that. If you cookie each user that arrives on your server, you could create some middleware that would keep track of how many page requests in some recent time interval have come from the browser with this cookie and just return them an error page that explains they can't make requests that quickly. I would probably implement this at the web page level, not the webSocket level as that will give users better feedback to stop hitting refresh. If it's really a refresh you're trying to protect against and not general navigation on your site, then you can keep a record of a combination cookie and URL and if you see even two of those within a few seconds, then return the error page instead of the expected content. If you redirect to an error page, it forces a more conscious action to go back to the right page again before they can get to the content.

web socket connection closed when behind proxy

I've a web sockets based chat application (HTML5).
Browser opens a socket connection to a java based web sockets server over wss.
When browser connects to server directly (without any proxy) everything works well.
But when the browser is behind an enterprise proxy, browser socket connection closes automatically after approx 2 minutes of no-activity.
Browser console shows "Socket closed".
In my test environment I have a Squid-Dansguardian proxy server.
IMP: this behaviour is not observed if the browser is connected without any proxy.
To keep some activity going, I embedded a simple jquery script which will make an http GET request to another server every 60 sec. But it did not help. I still get "socket closed" in my browser console after about 2 minutes of no action.
Any help or pointers are welcome.
Thanks
This seems to me to be a feature, not a bug.
In production applications there is an issue related with what is known as "half-open" sockets - see this great blog post about it.
It happens that connections are lost abruptly, causing the TCP/IP connection to drop without informing the other party to the connection. This can happen for many different reasons - wifi signals or cellular signals are lost, routers crash, modems disconnect, batteries die, power outages...
The only way to detect if the socket is actually open is to try and send data... BUT, your proxy might not be able to safely send data without interfering with your application's logic*.
After two minutes, your Proxy assume that the connection was lost and closes the socket on it's end to save resources and allow new connections to be established.
If your proxy didn't take this precaution, on a long enough timeline all your available resources would be taken by dropped connections that would never close, preventing access to your application.
Two minutes is a lot. On Heroku they set the proxy for 50 seconds (more reasonable). For Http connections, these timeouts are often much shorter.
The best option for you is to keep sending websocket data within the 2 minute timeframe.
The Websocket protocol resolves this issue by implementing an internal ping mechanism - use it. These pings should be sent by the server and the browser responds to them with a pong directly (without involving the javascript application).
The Javascript API (at least on the browser) doesn't let you send ping frames (it's a security thing I guess, that prevents people from using browsers for DoS attacks).
A common practice by some developers (which I think to be misconstructed) is to implement a JSON ping message that is either ignored by the server or results in a JSON pong.
Since you are using Java on the server, you have access to the Ping mechanism and I suggest you implement it.
I would also recommend (if you have control of the Proxy) that you lower the timeout to a more reasonable 50 seconds limit.
* The situation during production is actually even worse...
Because there is a long chain of intermediaries (home router/modem, NAT, ISP, Gateways, Routers, Load Balancers, Proxies...) it's very likely that your application can send data successfully because it's still "connected" to one of the intermediaries.
This should start a chain reaction that will only reach the application after a while, and again ONLY if it attempts to send data.
This is why Ping frames expect Pong frames to be returned (meaning the chain of connection is intact.
P.S.
You should probably also complain about the Java application not closing the connection after a certain timeout. During production, this oversight might force you to restart your server every so often or experience a DoS situation (all available file handles will be used for the inactive old connections and you won't have room for new connections).
check the squid.conf for a request_timeout value. You can change this via the request_timeout. This will affect more than just web sockets. For instance, in an environment I frequently work in, a perl script is hit to generate various configurations. Execution can take upwards of 5-10 minutes to complete. The timeout value on both our httpd and the squid server had to be raised to compensate for this.
Also, look at the connect_timeout value as well. That's defaulted to one minute..

For a push notification, is a websocket mandatory?

I have PHP on the server side, and HTML and javascript on the client side.
I am making an app where a stakeholder types a message that is broadcasted to multiple recievers of a group in real time.
I did some research on google and I understand I need to use WebSockets or Comet for real time push notifications. Is WebSocket or Comet mandatory for sending mass notifications to users?
Is my understanding correct? Any references to start with?
If the client is a browser, then the ONLY two ways a standard browser can connect to a server is via an Ajax (e.g. http) request or a webSocket connection. So, if you want a client to get notified of something from the outside world it has to use one of those two mechanisms.
HTTP requests are transitory. The client makes a request of a server, the server responds. HTTP requests are perfect for the client requesting information from the server. They are not very good at the server sending information to the client because normally the client is not connected. There are hacks and work-arounds where the client "polls" the server on some interval and maybe even the server uses longer running requests to try to simulate a "push" type system, but they are sub-optimal hacks at best.
webSockets are continuous connections. The client connects and the connection remains in place for as long as both sides want. This allows either side the ability to send a message to the other side whenever they want. That means the server can "push" data to the client whenever it wants. webSockets are efficient for push connections and are recommended (this is one of the main things they were designed for).
Comet is a library that was originally built for using HTTP to try to "hack" or "simulate" push before webSockets were invented and then before they were widely supported. I can think of no reason why one would want to use Comet instead of a webSocket unless you had such an old browser that webSocket was not supported.
So, if you are trying to do "realtime server push" to a browser, then you must have a continuously connected socket from the client which means webSocket (or something built on top of webSocket like socket.io).
For phone apps where you have access to the phone SDK, you can use the "push" system built into the OS to push some messages from server to client. This isn't quite the same as the two way webSocket channel, but since you asked about "push notifications", the OS push services available in both Android and IOS could also be an option for pushing notifications from server to client. Here's info on iOS notifications and Google Cloud Messaging
As of 2016, one can also use Server-sent events in all modern browsers except Microsoft browsers (not supported yet in Edge or IE) to push data from server to client. Here's a browser compatibility table. Server-sent events use a long lasting HTTP connection, a special MIME type and a supporting client in order to be able to send events from server to client at any time. Unlike webSockets, server-sent events are one way only (from server to client). A client would then use a traditional Ajax call in order to be able to send data to a server (whereas with a webSocket data can be sent either way over the same webSocket connection).
Here's a good description of how server-sent events work: How do server-sent events actually work?
Is your client application a SPA? (Single Page application)?
It's very important because if not, you have to consider that everytime a client change page, connection with websocket server will be lost.
In this case you have to manage a queue because if stakeholder send a multicast request when one client is disconnected, client won't receive nothing.
Polling won't solve this situation too and it's an orrible solution because mobile clients (for example) with typical internet plan, will consume megabytes for unuseful "ping" traffic.
A real example of polling is a child in a car asking his dad every minute if they are arrived to a destination!
So, Is there a solution without using spa?
Yes, using a "shared storage" between stakeholder and clients, and using websocket only for "wake up" online clients saying: Hey there is something new, go to check!
Everytime a client open a page it will receive from backend also not-read notifications, taken from the storage.
When a stakeholder want to notify something, it will just store the notification message in the shared storage and send a "pulse" to notification server.
Notification server will forward the "pulse" to online clients (just in case someone is stuck reading a page).
If a "pulse" is lost because a client is changing page there is no problem because the client will bring notifications from the storage.
Every page will contain this logic:
Retrive number or unread notifications (server side)
Connect to the notification server after 5 seconds (javascript side).
Hope it helps.
I would suggest that using webSockets is a more efficient way compared to other options, why is this? Well when a client receives a notification that there's a change in the server there is no need to create an AJAX call to the server to get that change, it can be sent to the client with the same webSocket connection more easily than AJAX. This means efficient code and a faster running App!

How do I recover from a WebSocket client computer going to sleep or app going to background (Safari on iPad)

I have browser client Javascript which opens a WebSocket (using socket.io) to request a long-running process start, and then gets a callback when the process is done. When I get the callback, I update the web page to let the user know the process has completed.
This works ok, except on my iPad when I switch to another app and then come back (it never gets the callback, because I guess the app is not online at the time). I'm assuming the same thing will happen on a laptop or other computer that sleeps while waiting for the callback.
Is there a standard way (or any way) to deal with this scenario? Thanks.
For reference, if you want to see the problem page, it is at http://amigen.perfectapi.com/
There are a couple of things to consider in this scenario:
Detect the app going off/on line
See: Online and offline events.
When your app detects the online event after the computer wakes up you can get any information that you've missed.
For older web browsers you'll need to do this in a cleverer way. At Pusher we've added a ping - pong check between the client and server. If the client doesn't receive a ping within a certain amount of time it knows there's a connection problem. If the server sends a ping and doesn't get a pong back with a certain time it knows there's a problem.
A ping pong mechanism is defined in the spec but a way of sending a ping or pong hasn't been defined on the WebSocket API as yet.
Fetching missed information
Most realtime servers only deliver messages to connected to clients. If a client isn't connected, maybe due to temporary network disturbance or their computer has been asleep for a while, then those clients will miss the message.
Some frameworks do provide access to messages through a history/cache. For those that don't you'll need to detect the problem (as above) and then fetch any missed messages. A good way to do this is by providing a timestamp or sequence ID with each messages so you can make a call to your web server to say "give me all messages since X".

Categories

Resources