I'm developing a messaging app and I have to make a call to a server every x seconds to load from server the new messages.
I use a NSTimer that calls the server every x sec.
But for instance x = 1 sec and the response from server arrives after 1,5 sec. In this case I have one new request to the server that comes before that the previous request is satisfied, and this is a big problem for my app's logic. Can you help me to understand how can I check cyclically the messages on the server without have this problem?
Thank you.
Stop your timer before starting your web request, and then start it again when you get your answer.
You can send request to the server and once you have response (success/failure) send another one. In this scenario you will be sure that just one request is send and you can handle it easily.
Related
I'm experiencing slow response times for my first http POST request to my server.
This happens both in Android and iOS networking libraries. (Volley on Android, and Alamofire in iOS).
First response is roughly 0.7s-0.9s, whereas subsequent requests are 0.2s.
I'm guessing this is due to the session being kept-alive by the server, therefore eliminating the need for establishing a new session on each request.
I figure I can make a dummy request when the app starts to start the session, but it doesn't seem very elegant.
I also control the server side (Node.js) so if any configuration needs to be done there I can also try it.
Investigating a little further, I tried sending an https CONNECT request before issuing the first "real" POST request, and the behavior replicates.
After 30 seconds or so, the connection is dropped (probably at the iOS URLSession level, the load balancer is configured to keep connections as 60 seconds).
In theory this makes sense because setting up an https connection takes up several (12 total) packets and I'm on an inter continental connection.
So my solution is to send a CONNECT request when I expect the user to send a regular request.
My main question is how to detect the application termination by the end user when it was in the background (Suspended) to be able to send logout request to the server ?
We already have a timeout interval in the server to kill the session, but assume that the interval is 5 minutes so this means that the session will be alive for 5 minutes after the user terminated the app and anyone can sniff on the data and reuse it.
Notes:
We use HTTPS connection and SSL Certificate Pining.
We also implemented a heartbeat web service to be called by client app every fixed interval to tell the server to keep the session alive for this interval, if this web service didn't call for specific session, the server will kill this session.
Once your app is suspended you don't get any further notice before you are terminated. There is no way to do what you want.
Plus, the user could suspend your app to do something else (like play a game) and then not go back to your app for DAYS.
If you want to log out when the user leaves your app, do it on the willBeSuspended message. Ask for more background time and send a logout right then and there.
Mohamed Amer,
Here is an approach used by Quickblox Server and I feel its pretty much solid though it involves a little overhead.
Once the client application (either iOS android) establishes the session with quickblox server, quickblox server expects the client application to send the presence information to server after a regular interval continuously.
Sending the presense information is pretty much simple. They have written a api which we keep hitting after a interval of 5 mins with session id that we have. They validate the session id and once found valid they will extend the expiration time for the user ascociated with that id for 5 mins more.
What they will do I believe is that,
Approach 1 : they maintain the last hit time and for all the subsequesnt request they check if the request time is within the the time frame of 5 min if yes simply process it. If the request comes after 5 min they will delete the session id for the user and respond saying you have timeout the session.
Approach 2 : Because they provide online and offline info as well they cant simply depend on the incoming request to delete the session id from server so they probably create a background thread which swipes over the db to find the entry with last hit time greater then 5 min and removes it from DB. and declares the user session expired.
Though this involves client apps continously hitting the server and increases the burden on the server for the app like chat application in which presense information is so vital this overhead is still fine i believe.
Hope I have provided you with some idea at least :)
I have an iOS application where I POST transactions to an API each time a transaction is completed. Once I get a 200 response code from the server I update an attribute on the transaction:
newTransaction.Synced = true
Incase the network connection ever drops I also POST every transaction where Synced = false when Reachability detects a network connection.
In perfect network conditions this works wells. However when I enable the Network Link Conditioner on my iPad and set packet loss to say 40% I start to see duplicated transactions on my server. What I assumed was happening is that it was taking longer than 30 seconds (the client side timeout on the request) to send my request and get the response from the server due to the high packet loss.
To confirm this, I made my API Sleep for 40 seconds for each web request and disabled Network Link Conditioner. As expected, the iOS app never set the Synced attribute to true as it was timing out before it got the response. However the server still created the entity for each POST request that was generated each time the iOS app launched or got network connectivity.
What's the best way to handle this situation so that duplicates never occur? I did think of adding a GUID to the transaction and then coding the API not to re-add the transaction if the GUID already exists. However the flip side is the iOS app would still never know the transaction has successfully synced. Is there a better way to handle this? Perhaps a timeout on the request which the server also adheres to?
Your Idea of assigning the GUID to transaction is good, but you might need to maintain a table on client side (browser memory) which will hold a record of all the calls you made to server and never heard back.
I'm developing a messaging system in Delphi. I'm using idTcpServer in my Server Application and idTcpClient in my client application. the client application pings the server every 10 seconds to see if the connection is active and tell the server to set the status of the user to Online. and also the user may send messages to his contacts. all these requests are followed by a response from server which i get by socket.readln command right after i send the request. for example for pinging the server:
TcpClient.socket.writeln('i am online');
if TcpClient.socket.readln = 'ok' then
begin
{commands}
end;
I also check for new messages using Long Polling. I send 'check for new messages ' + timestamp from tcpClient and then on the server, I check the database for new messages newer than the timestamp i recieved in a While loop so when there is a new message the loop breaks and notification is sent to the client.
But this system doesn't work for me. Sometimes I get the responses intended to be for checking for new messages when the client application is pinging the server.
I have developed the same system in php without a problem. but here there must be a problem.
I think it is not asynchronous. what should I do?
Regarding the check for new messages request, the server should not be looping waiting for new messages to arrive. Either there are new messages available at the time of the request or there are not. Get the request, do the query, report the result, and move on. The client can send a new check for new messages request periodically. Alternatively, have the client tell the server one time that it wants new messages, and then the server can actively push new messages to the client in real-time as they arrive on the server, instead of polling for them (similar to IMAP's IDLE command).
I would suggest you redesign your communication protocol to run asynchronously. Most modern IM services are asynchronous. When the client sends a request, do not expect a reply right away. Just let the client move on to other things. Have it run a separate timer/thread that reads all inbound data. When a reply does arrive, the client can act on it. If needed, include an identifier in the request that gets echoed in the reply so the client can keep track of the requests it sends. This also allows the server to use asynchronous processing on its end, so if a request takes a long time to run, the server can push it off to another thread/process and continue processing other requests in the meantime. Send the final reply when it is ready.
I am developing a VoIP app. When my app is in background I need to check if the server is still there. So I am trying to use setKeepAliveTimeout:handler: to make polls to server while app is in background.
The question is: how to ensure that I receive response or timeout within 5 seconds after I have sent poll message to server? If I don't receive response/timeout within 5 seconds the next opportunity to know that server is dead is only after keepAliveTimeout time which is not that good.
As I understand I can't setup NSTimer in setKeepAliveTimeout:handler: since we are in background (and NSTimer relies on run loop).
I see other possibility which is: make while loop and check for the current time in it. Although I would like to avoid making busy loops.
Could you please suggest me how can I achieve needed behaviour?