we wrote in C++ a screen sharing application based on sending screenshots.
It works by establishing a TCP connection btw the server and client, where the server forwards every new screenshot received for a user through the connection, and this is popped-up by the client.
Now, we are trying to host this on google app engine, and therefore need 'servlet'-ize and 'sandbox' the server code, so to implement this forwarding through HTTP requests.
I immagine the following:
1. Post request with the screenshot as multiple-data form (apache uploads ..).
But now the server needs to contact the specified client (who is logged in) to send it/forward the screenshot.
I'm not sure how to 'initiate' such connection from the servlet to the client. The client doesn't run any servlet environment (of course).
I know HTTP 1.1 mantains a TCP connection, but it seems gapps won't let me use it.
1 approaches that comes to mind is to send a CONTINUE 100 to every logged in user at login, and respond with the screenshot once it arrives. Upon receival the client makes another request, and so on.
an alternative (insipired from setting the refresh header for a browser) would be to have the app pool on a regular basis (every 5 secs).
You're not going to be able to do this effectively on GAE.
Problem 1: All output is buffered until your handler returns.
Problem 2: Quotas & Limits:
Some features impose limits unrelated
to quotas to protect the stability of
the system. For example, when an
application is called to serve a web
request, it must issue a response
within 30 seconds. If the application
takes too long, the process is
terminated and the server returns an
error code to the user. The request
timeout is dynamic, and may be
shortened if a request handler reaches
its timeout frequently to conserve
resources.
Comet support is on the product roadmap, but to me your app still seems like a poor fit for a GAE application.
Long Polling is the concept used for such asynchronous communications between server and client.
In Long Polling, servlet keeps a map of client and associated messages. Key of Map being client id and value being list of messages to be sent to the client. When a client opens a connection with server (sends request to a servlet), the servlet checks the Map if there are any messages to be sent to it. If found, it sends the messages to the client exits from the method. On receiving messages, the client opens a new connection to the server. If the servlet does not find any messages for given client, it waits till the Map gets updated with messages for given client.
This is a late reply, I'm aware, but I believe that Google have an answer for this requirement: the Channel API.
Related
We are making a web application in Go with a MySQL database. Our users are allowed to only have one active client at a time. Much like Spotify allows you to only listen to music on one device at a time. To do this I made a map with as key the user ids and a reference to their active websocket connection as a value. Based on the websocket id that the client has to send in the header of the request we can identify weather the request comes from their active session.
My question is if it's a good practice to store data (in this case the map with the user ids and websockets) in a global space or is it better to store it in the database.
We don't expect to reach over 10000 simultaneously active clients. Average is probably gonna be around 1000.
If you only run one instance of the websocket server storing it in memory should be sufficient. Because if it for some reason goes down/restarts then all the connections will be lost and all the clients will have to create them again (and hence the list of connection will once again be populated by all the clients who want to use the service).
However, if you plan on scaling it horizontally so you have multiple websocket services behind a load balancer, then the connections may need to be stored in a database of some sort. And not because it necessarily needs to be more persistant but because you need to be able to check the request against all the services connections.
It is also possible to have a separate service which handles the incoming request and asks all the websocket services if any of them have the connection specified in the request. This could be done if you add a pub/sub queue and every websocket service subscribes to channels for all its websocket ids and the service that receives the request then publishes the websocket id, and the websocket services can then send back replies on a separate channel if they have that connection. You must decide how to handle if no one is responding (no websocket service has the websocket id). Either the channel does not exist, or you expect the answer within a specific time. Or you could publish the question on a general topic and expect all the websocket services to reply (yes or no).
And regarding whether you need to scale it I guess depends mostly on the underlying server you're running the service on. If I understand it correctly the websocket service will basically not do anything except from keeping track of its connections (you should add some ping pong to discover if connections are lost). Then your limitation should mainly be on how many file descriptors your system can handle at once. If that limit is much larger than your expected maximum number of users, then running only one server and storing everything in memory might be an OK solution!
Finally, if you're in the business of having a websocket open for all users, why not do all the "other" communication over that websocket connection instead of having them send HTTP requests with their websocket id? Perhaps HTTP fits better for your use case but could be something to think about :)
My application allows a user to enter a URL of an article he/she wishes to analyze. It goes through our API gateway to reach the correct services engaged in this process. The analysis takes between 5 and 30 seconds depending on the article's word count.
For now, my reactjs client sends the request to the API and waits for 5 to 30 seconds to receive the response. Is there a better way to handle this such as enqueuing the job and let the API ping the client (reactjs frontend) once it has been done?
Server-sent Events (SSEs) allow your server to push new information to your browser, and hence look ideal to me for this purpose. They work over HTTP and there is good support for all browsers except for IE.
So the new process could look as follows:
Client send request to server, which initiates the lookup and potentially responds with the topic the browser needs to subscribe to (in case that's unique per lookup)
Server does its thing and sends updates as it processes new content. See how the beauty of this is that you could inform your client about partial updates.
If SSEs is not an option to you, you could leverage good old Websockets for bi-directional communication, but for such a simple endeavor, it might be too much technology to solve the problem.
A third alternative, especially if you are talking amongst services (no web or mobile clients on the other side) is to use web-hooks, so that the interested party would expose and listen on a specific endpoint, that the publisher (the server that does the processing) would write updates to.
Hope this is useful.
Let's say we have several clients connected to App Engine using Channel API. Each client sends messages, which should be propagated to other conntected clients according to some rules. The tricky part is that clients may not be to the same App Engine instance.
Is there any way to push data from one instance to the others?
(Yes, I know about Memcache, but this would require some kind of polling.)
You're asking two questions here.
a. Can you push data from one instance to another without the use of polling. The answer is generally no.
b. Can one client send messages to the server that can be propagated to other clients? Yes, and this does not require propagating messages to other server-side instances.
Consider the Channel API as a service. Clients are connected to the Channel API service; they are not connected to any particular instance. Therefore any instance can send messages to any client.
You'll need to store the Channel tokens of your clients in the datastore, in some way that's queryable to match your rules.
Your client makes an HTTP request to send a message to your server.
The handler on the server queries for channel tokens that it needs to propagate the message to (either from memcache or datastore).
The handler on the server sends messages to all the clients.
If the list of destination clients is extremely large, you might want to do steps 3/4 in a task queue where the operation can run longer.
It does not matter what instance a client is connected to, that's hidden from you by the API.
Clients can only "reply" to message via standard HTTP commands, they don't actually have any way to respond via the channel API directly.
So Client A on server A1 wants to sent a message to client B on server B1.
Client A posts to a handler. That might be instance A1 or B1. It does not matter which as the server now passes the message on to client B whatever server client B is connected to via the Channel API.
The real point is that no App Engine instance has any data at all, in general. So it does not matter which instance you connect to, it might be the 99th instance or the very first to start up. So you have to design your application so that it's irrelevant what instance is in use.
Client sends message to server via HTTP.
Server sends message to N clients via the channel API.
Channel API does not make a fixed frontend-instance-to-client connection. Any frontend instance can push message to channel if it knows the channel ID.
What you need to do is pass messages cross-channel.
User one sends message normally to server (e.g. via GET)
Server looks up channel ID of second user and pushes the message
Repeat procedure in other direction: second user to first user.
in a Silverlight application, we used to send requests from client to server and receive its response.
is it possible to send an information from server to client which is not waiting for? for example server ask client to update a text in a special text box and so on. "an info or known command which may come to client any time and is not a response to the client's request"?
You can use Duplex Services for this.
I've read that Silverlight 2.0 imposes by design an asynchronous model when communicating with the web server. I haven't had a chance to experiment with Silverlight, but I assume that it uses a thread-pool to manage threads like in the .NET Framework.
Now, since some browsers, most notably Internet Explorer, have an hard-coded limit of maximum two concurrent HTTP connections that can be made on the web server, what happens if I make a bunch of asynchronous requests from Silverlight?
Does Silverlight bypass this limitation in the web browser and open as many HTTP connections as there are threads available, or do the asynchronous requests queue up and wait for one of the two connections to become available?
In IE (haven't tested others) Silverlight is restricted to 2 connections at a time.
The behavior in Silverlight is to simply not make the request. So if you make 5 Async web service requests right in a row, the first 2 will happen, the other three won't. No exception is thrown that i've seen...
Fiddler is a big help here :)
Create a messaging manager interface for your client. Any outgoing request are posted to a queue that this manager processes against. It would serially process queued messages (i.e., when the call back of the last message sent to the server is invoked, can then safely proceed to process the next queued message).
You can consume the other connection resource by keeping a Comet connection open to the server. The server would push any return messages to the client via this Comet connection. You'll need to stamp out-going messages with a unique number that can be embedded as a property on in-coming messages - so that results can be correlated to request. The messaging manager would dispatch a result message to the appropriate handler for that result.
Essentially you end up using two connection resources to establish bi-directional messaging. But there is no artificial limit on the number of requesters on the client (though request will get serially transmitted to the server). The act of sending is always fast, though, because you don't wait for any result to be computed - you just need to deliver the message reliably to the server and return. Results come back asynchronously on the other Comet connection.
We do something along these lines with our Flex client apps in conjunction to Adobe BlazeDS running in our Tomcat web server:
A Flex-based asynchronous stack
Firefox is also limited to two connections, in addition to IE as stated already.
Note that the limit is per hostname.
If you add entries to your hosts file, or use dns aliases you can get more connections. For example in testing, add lines like '127.0.0.1 test1' to your hosts file, and then you can open two connections to http://localhost and two more to http://test1
I guess, being a .NET application Silverlight 2 has an independent from browser limit.
I would assume It is maxconnection attribute in Machine.config as mentioned in http://support.microsoft.com/kb/828219
Firstly the Machine.config file would not be used as the Silverlight control is sandboxed with its own version of the CoreCLR.
I believe that the Silverlight control actually makes use of the underlying browser to make the asynchronous HTTP requests. This is most likely the case considering how the Silverlight control can't gain access to SOAP fault information as the SOAP specification requires that the server returns an HTTP 500 response code and the Silverlight control doesn't get that from the browser hosting the control.
This post here serves to confirm this.
As to the limit of concurrent HTTP connections, I believe IE5 and later limit the number of connections to the same site based on HTTP protocol version - HTTP/1.0 it limits to 4 connections and HTTP/1.1 to 3 connections. Most of the time the web server will limit the number of connections to 2 per client, queueing or discarding the remainder.