Why GCDAsyncSocket always disconnect afters read timeout? - ios

I looked into GCDAsyncSocket.m at the code that handles read timeout. If I don't extend the timeout, it seems that socket got closed and there is no option to the socket alive keep. I can't use infinite timeout (timeout = -1) because I still need to know when it is timed out, but also doesn't want it to disconnect. I'm not sure there is a reason behind this. Does anyone know?
- (void)doReadTimeoutWithExtension:(NSTimeInterval)timeoutExtension
{
if (currentRead)
{
if (timeoutExtension > 0.0)
{
currentRead->timeout += timeoutExtension;
// Reschedule the timer
dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (timeoutExtension * NSEC_PER_SEC));
dispatch_source_set_timer(readTimer, tt, DISPATCH_TIME_FOREVER, 0);
// Unpause reads, and continue
flags &= ~kReadsPaused;
[self doReadData];
}
else
{
LogVerbose(#"ReadTimeout");
[self closeWithError:[self readTimeoutError]];
}
}
}
FYI, there is a pull request at https://github.com/robbiehanson/CocoaAsyncSocket/pull/126 that adds this keep-alive feature but it is not pulled yet.

I am the original author of AsyncSocket, and I can tell you why I did it that way: there are too many ways for protocols to handle timeouts. So I implemented a "hard" timeout and left "soft" timeouts up to the application author.
The usual way to do a "soft" timeout is with an NSTimer or dispatch_after. Set one of those up, and when the timer fires, do whatever you need to do. Meanwhile, use an infinite timeout on the actual readData call. Note that infinite timeouts aren't actually infinite. The OS will still time out after, say, 10 minutes without successfully reading. If you really want to keep the connection alive forever, you might be able to set a socket option.

Related

Gumming up the works with ThreadPool

I am having issues trying to get the status of how many things are left to process using SignalR. I have a starting number and every time an item completes I have it increment a counter. However, the user isn't being notified in the manner the code would suggest.
I'm not entirely sure how to word this, but here goes. I'm queuing up a series of passengers to process and then processing them. If my understanding is correct, the processing starts immediately after the first thread is queued. After everyone is queued, every second there is a SignalR call to inform the user of where we are in the process. However, the SignalR call isn't working as expected.
Next, code:
StatusInfo.SendStatus("Retrieving Passenger Details");
foreach (var passenger in manifestResponse.Manifest.PassengerList)
{
//Spin up all the threads.
PassengerThreads++;
TotalPassengers++;
//StatusInfo.SendStatus(TotalPassengers - PassengerThreads, 0, TotalPassengers, StartTime);
ThreadPool.QueueUserWorkItem(new WaitCallback(GetSinglePassengerDetails), passenger);
if (TotalPassengers % 5 == 0)
{
StatusInfo.SendStatus(TotalPassengers - PassengerThreads, 0, TotalPassengers, StartTime);
}
}
//Wait for them to be done.
do
{
StatusInfo.SendStatus(TotalPassengers - PassengerThreads, 0, TotalPassengers, StartTime);
Thread.Sleep(1000);
}
while (PassengerThreads > 0);
So what it happening is that I will send the threads to the pool to run, however, during the send status loop it does not actually send anything back. When I open the console in the browser there's a 20 second gap between showing "Retrieving Passenger Details" and the first X of Y status. Is there something I'm doing wrong here? Maybe using the wrong threading model? Thanks.

Playing sound at interval with GCD timer not behaving as expected

Hi !
I'm building a timer using GCD for the purpose of playing a sound at a specific interval, to be more precise, it's a metronome sound. I've been trying for days to solve my issue but nothing. Everything is good but when I set my tempo to a bigger value , let's say 150 bpm or 200 bpm, when the sound starts for the first time, it fires very quickly(almost like two sounds in the same time meaning it does not have the expected interval) and after this , it calibrates. I start the sound the second time , all is good... so this happens only the first time I resume my dispatch source so I'm guessing it has something to do with loading the sound from the disk , like in this post : Slow start for AVAudioPlayer the first time a sound is played . For my sound I used at first an instance of AVAudioPlayer with prepareToPlay and play and also created it in the AppDelegate class, it hasn't work...I have even tried the SoundManager class developed by #NickLockwood,same issue. At present, I'm using a SystemSoundID. As for the timers, this is my first GCD timer , I've already tried the classical NSTimer, CADisplayLink and other timers found on git... all in vain.
Another interesting issue is that with the other timers , everything is perfect on the simulator but on the device the same glitch.
Here's the code, I hope someone will bring me to the light.
-(void)playButtonAction //
{
if (_metronomeIsAnimatingAndPLaying == NO)
{
[self startAnimatingArm]; // I start my animation and create my timer
metronomeTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
dispatch_source_set_timer(metronomeTimer,dispatch_time(DISPATCH_TIME_NOW, duration * NSEC_PER_SEC),duration * NSEC_PER_SEC,duration *NSEC_PER_SEC);
dispatch_source_set_event_handler(metronomeTimer, ^{[self playTick];});
dispatch_resume(metronomeTimer);
_metronomeIsAnimatingAndPLaying = YES;
}
}
-(void)playTick
{
AudioServicesPlaySystemSound(appDeleg.soundID); // soundID is created in appDelegate
}
In my application didFinishLaunching
NSString *path = [[NSBundle mainBundle] pathForResource:#"tick"
ofType:#"caf"];
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path]
, &_soundID);
And BPM setter and getter :
- (NSUInteger)bpm
{
return round(60.0 / duration);
}
- (void)setBpm:(NSUInteger)bpm
{
if (bpm >= MaxBPM) {
bpm = MaxBPM;
} else if (bpm <= MinBPM) {
bpm = MinBPM;
}
duration = (60.0 / bpm);
}
This arrangement will fundamentally never work.
GCD is a thread-pool designed to facilitate task-level parallelism. It is usually asynchronous and non real-time. These are almost precisely the opposite characteristics to those required in an audio application.
Each thread servicing a GCD queue is contending with other threads in the system for an opportunity to execute. Furthermore, the queue may be busy at requested time processing something else. If that something else is long-running - and long-running tasks are precisely the kind of thing that GCD is made for - the scheduler may pre-empt the thread before the operation has completed and penalise the queue; it may wait a long time for service.
The Manpage for GCD states the following about timers on GCD queues:
A best effort attempt is made to submit the event handler block to the target queue at the specified time; however, actual invocation may occur at a later time.
NSTimer will not be any better. Its documentation states A timer is not a real-time mechanism. Since you'll probably run this on the application's main run-loop, it will also be very unpredictable.
The solution to this problem is to use lower-level audio APIs - specifically Audio Units. The advantage of doing so is that soft-syth units have an event queue which is serviced by the unit's render handler. This runs on a real-time thread, and offers extremely robust and predictable service. Since you can queue a considerable number of events with timestamps in the future, your timing requirements are now quite loose. You could safely use either GCD or a NSTimer for this.

NSRunLoop's runMode:beforeDate: - the correct approach for setting the "beforeDate"

I have a doubt regarding the correct usage of NSRunLoop's runMode:beforeDate method.
I have a secondary, background thread that processes delegate messages as they are received.
Basically, I have process intensive logic that needs to be executed on a background thread.
So, I have 2 objects, ObjectA and AnotherObjectB.
ObjectA initializes AnotherObjectB and tells AnotherObjectB to start doing it's thing. AnotherObjectB works asynchronously, so ObjectA acts as AnotherObjectB's delegate. Now, the code that needs to be executed in the delegate messages, needs to be done on a background thread. So, for ObjectA, I created an NSRunLoop, and have done something like this to set the run loop up:
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (aCondition);
Where aCondition is set somewhere in the "completion delegate message".
I'm getting all my delegate messages and they are being processed on that background thread.
My question being: is this the correct approach?
The reason I ask this is because [NSDate distantFuture] is a date spanning a couple of centuries. So basically, the runLoop won't timeout until "distantFuture" - I definitely won't be using my Mac or this version of iOS till then. >_<
However, I don't want the run loop to run that long. I want the run loop to get done as soon as my last delegate message is called, so that it can properly exit.
Also, I know that I can set repeating timers, with shorter intervals, but that is not the most efficient way since it's akin to polling. Instead, I want the thread to work only when the delegate messages arrive, and sleep when there are no messages. So, is the approach I'm taking the correct approach, or is there some other way of doing it. I read the docs and the guide, and I set this up based off what I understood from reading them.
However, when not completely sure, best to ask this awesome community for an opinion and confirmation.
So, thanks in advance for all your help!
Cheers!
The code is in the docs:
If you want the run loop to terminate, you shouldn't use this method. Instead, use one of the other run methods and also check other arbitrary conditions of your own, in a loop. A simple example would be:
BOOL shouldKeepRunning = YES; // global
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
where shouldKeepRunning is set to NO somewhere else in the program.
After your last "message", un-set shouldKeepRunning (on the same thread as the run loop!) and it should finish. The key idea here is that you need to send the run loop an event so it knows to stop.
(Also note that NSRunLoop is not thread-safe; I think you're supposed to use -[NSObject performSelector:onThread:...].)
Alternatively, if it works for your purposes, use a background a dispatch queue/NOperationQueue (but note that code which does this shouldn't touch the run loop; things like starting a NSURLConnection from a dispatch queue/NSOperationQueue worker thread will likely cause problems).
The reason I ask this is because [NSDate distantFuture] is a date spanning a couple of centuries.
The method runMode:beforeDate: will
return NO immediately if there are no sources scheduled on the RunLoop.
return YES whenever an event has been processed.
return YES when the limitDate has been reached.
So even if the limitDate is very high, it will return after every processed event, it will not keep running until limitDate has been hit. It would only wait for that long if no event is ever processed. limitDate is thus like a timeout after that the method will give up on waiting for an event to take place. But if you want to have multiple events in a row handled, you must call this method over and over again, hence the loop.
Think of fetching packets with timeout from a network socket. The fetch call returns when a packet arrives or when the timeout has been hit. Yet if you want to process the next packet, you must call the fetch method again.
The following is unfortunately pretty bad code for two reasons:
// BAD CODE! DON'T USE!
NSDate * distFuture = NSDate.distantFuture;
NSRunLoop * runLoop = NSRunLoop.currentRunLoop;
while (keepRunning) {
[runLoop runMode:NSDefaultRunLoopMode beforDate:distFuture];
}
If no RunLoopSource is yet scheduled on the RunLoop, it will waste 100% CPU time, as the method will return at once just to be called again and that as fast as the CPU is able to do so.
The AutoreleasePool is never renewed. Objects that are autoreleased (and even ARC does that) are added to the current pool but are never released as the pool is never cleared, so memory consumption will raise as long as this loop is running. How much depends on what your RunLoopSources are actually doing and how they are doing it.
A better version would be:
// USE THIS INSTEAD
NSDate * distFuture = NSDate.distantFuture;
NSRunLoop * runLoop = NSRunLoop.currentRunLoop;
while (keepRunning) #autoreleasepool {
BOOL didRun = [runLoop runMode:NSDefaultRunLoopMode beforDate:distFuture];
if (!didRun) usleep(1000);
}
It solves both problems:
An AutoreleasePool is created the first time the loop runs and after every run it is cleared, so memory consumption will not raise over time.
In case the RunLoop didn't really run at all, the current thread sleeps for one millisecond before trying again. This way the CPU load will be pretty low since as as no RunLoopSource is set, this code only runs once every millisecond.
To reliably terminate the loop, you need to do two things:
Set keepRunning to NO. Note that you must declare keepRunning as volatile! If you don't do that, the compiler may optimize the check away and turn your loop into an endless loop since it sees no code in the current execution context that would ever change the variable and it cannot know that some other code somewhere else (and maybe on another thread) may change it in the background. This is why you usually need a memory barrier for these cases (a lock, a mutex, a semaphore, or an atomic operation), as compilers don't optimize across those barriers. However, in that simple case, using volatile is enough, as BOOL is always atomic in Obj-C and volatile tells the compiler "Always check thes value of this variable as it may change behind your back without you seeing that change at compile time".
If the variable has been changed from another thread and not from within an event handler, your RunLoop thread may be sleeping inside the runMode:beforeDate: call, waiting for a RunLoopSource event to take place which may take any amount of time or never happen at all anymore. To force this call to return immediately, just schedule an event after changing the variable. This can be done with performSelector:onThread:withObject:waitUntilDone: as shown below. Performing this selector counts as a RunLoop event and the method will return after the selector was called, see that the variable has changed and break out of the loop.
volatile BOOL keepRunning;
- (void)wakeMeUpBeforeYouGoGo {
// Jitterbug
}
// ... In a Galaxy Far, Far Away ...
keepRunning = NO;
[self performSelector:#selector(wakeMeUpBeforeYouGoGo)
onThread:runLoopThread withObject:nil waitUntilDone:NO];

iOS: How to check if a stream connection is timed out

In my application I connect to a server using
- (void)connectToServerUsingCFStream:(NSString *) urlStr portNo: (uint) portNo
This function is called by another method
- (void)connectToServer:(NSString *)serverName onPort:(int)portNo
{
[self connectToServerUsingCFStream:serverName portNo:portNo];
while (!((iStream.streamStatus == 2) || (oStream.streamStatus == 2))) {
continue;
}
NSLog(#"Streams connected");
[self sendLoginRequest];
}
Now I want to know wether there is an easy possibility to check if my connection request is timed out (maybe with a certain time value?). Is there a way to handle this in my while loop or should I use something different?
Thanks in advance,
Bautzi
I have no idea how you exactly implement the connection, but here I have some connection codes from the XMPPFramework , as the code comments:
/**
* XMPPReconnect handles automatically reconnecting to the xmpp server due to accidental disconnections.
* That is, a disconnection that is not the result of calling disconnect on the xmpp stream.
*
* Accidental disconnections may happen for a variety of reasons.
* The most common are general connectivity issues such as disconnection from a WiFi access point.
*
* However, there are several of issues that occasionaly occur.
* There are some routers on the market that disconnect TCP streams after a period of inactivity.
* In addition to this, there have been iPhone revisions where the OS networking stack would pull the same crap.
* These issue have been largely overcome due to the keepalive implementation in XMPPStream.
*
* Regardless of how the disconnect happens, the XMPPReconnect class can help to automatically re-establish
* the xmpp stream so as to have minimum impact on the user (and hopefully they don't even notice).
*
* Once a stream has been opened and authenticated, this class will detect any accidental disconnections.
* If one occurs, an attempt will be made to automatically reconnect after a short delay.
* This delay is configurable via the reconnectDelay property.
* At the same time the class will begin monitoring the network for reachability changes.
* When the reachability of the xmpp host has changed, a reconnect may be tried again.
* In addition to all this, a timer may optionally be used to attempt a reconnect periodically.
* The timer is started if the initial reconnect fails.
* This reconnect timer is fully configurable (may be enabled/disabled, and it's timeout may be changed).
*
* In all cases, prior to attempting a reconnect,
* this class will invoke the shouldAttemptAutoReconnect delegate method.
* The delegate may use this opportunity to optionally decline the auto reconnect attempt.
*
* Auto reconnect may be disabled at any time via the autoReconnect property.
*
* Note that auto reconnect will only occur for a stream that has been opened and authenticated.
* So it will do nothing, for example, if there is no internet connectivity when your application
* first launches, and the xmpp stream is unable to connect to the host.
* In cases such as this it may be desireable to start monitoring the network for reachability changes.
* This way when internet connectivity is restored, one can immediately connect the xmpp stream.
* This is possible via the manualStart method,
* which will trigger the class into action just as if an accidental disconnect occurred.
**/
I don't know if this XMPPReconect class meets your demand.

recv() windows socket takes infinite time - how to timeout?

I use file descriptors to find the readable sockets and go on to read. For some reasons, a socket that has no data on the wire, goes on to read and never returns. Is there a way I can come out of the receive after a timeout?
I am using winsock library..
http://tangentsoft.net/wskfaq/newbie.html#timeout
2.15 - How can I change the timeout for a Winsock function?
Some of the blocking Winsock functions (e.g. connect()) have a timeout embedded into them. The theory behind this is that only the stack has all the information necessary to set a proper timeout. Yet, some people find that the value the stack uses is too long for their application; it can be a minute or longer.
You can adjust the send() and recv() timeouts with the SO_SNDTIMEO and SO_RCVTIMEO setsockopt() options. .
For other Winsock functions, the best solution is to avoid blocking sockets altogether. All of the non-blocking socket methods provide ways for you to build custom timeouts:
Non-blocking sockets with select() – The fifth parameter to the select() function is a timeout value.
Asynchronous sockets – Use the Windows API SetTimer().
Event objects – WSAWaitForMultipleEvents() has a timeout parameter.
Waitable Timers – Call CreateWaitableTimers() to make a waitable timer, which you can then pass to a function like WSAEventSelect() along with your sockets: if none of the sockets is signalled before the timer goes off, the blocking function will return anyway.
Note that with asynchronous and non-blocking sockets, you may be able to avoid handling timeouts altogether. Your program continues working even while Winsock is busy. So, you can leave it up to the user to cancel an operation that’s taking too long, or just let Winsock’s natural timeout expire rather than taking over this functionality in your code.
your problem is in the while loop that you try to fill buffer
just put an if statement that check last index of every chunks for '\0'
then break your while loop
do {
len = rcv(s,buf,BUF_LEN,0);
for (int i = 0; i <= len; ++i) {
if (buf[i] >= 32 || buf[i] == '\n' || buf[i] == '\r') { //only write valid chars
result += buf[i]; //final string
}
}
if (buf[len] == '\0') { //buf[len] is the last position in the received chanks
break;
}
} while (inner_result > 0);

Resources