Ecuador
Ecuador

Reputation: 1177

CocoaAsyncSocket fallback for failed/unsupported commands

Although I am a rather "seasoned" developer, I've never actually needed to program sockets, apart from a perl project where I did both client and server, so everything was under my control. Hence, forgive me if I am going the wrong way and not doing something obvious. So, the problem is this: I want my iOS app to communicate to a device. The devices might have variations of firmware, one firmware might support CMD1, the other CMD2 and the only way to know is to actually try them - if a command is supported it returns 1, otherwise it does nothing. I found this nice CocoaAsyncSocket library which seems easy to use and got everything working, except the part I described, i.e. finding out when CMD1 is not supported and I have to switch to CMD2, which I can only do in a very "hacky" way:

So I write the command and expect to read 1 as a response:

[socket writeData:[@"CMD1" dataUsingEncoding:NSASCIIStringEncoding] withTimeout:0.1 tag:TAG1];
[socket readDataToLength:1 withTimeout:0.5 tag:TAG1];

To catch the unsupported command case, I don't see any zero length reads, so reading the available delegate functions I expected the closest thing would be to do something like:

- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length {
    if (tag == TAG1) {
        NSLog(@"No response, trying CMD2");
        [socket writeData:[@"CMD2" dataUsingEncoding:NSASCIIStringEncoding] withTimeout:0.1 tag:TAG2];
        [socket readDataToLength:1 withTimeout:0.5 tag:TAG2];
    }
    return 0;
}

However, while the code above is called, there is a disconnect with a read timeout error, and the writeData/readData commands above don't actually end up doing anything. Instead, I found that I can make it work on the disconnection delegate:

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)error {
    if ([error.domain isEqualToString:@"GCDAsyncSocketErrorDomain"] && error.code == GCDAsyncSocketReadTimeoutError) {
        [socket writeData:[@"CMD2" dataUsingEncoding:NSASCIIStringEncoding] withTimeout:0.1 tag:TAG2];
        [socket readDataToLength:1 withTimeout:0.5 tag:TAG2];
    }
}

This actually works, but it is a "hacky" way of doing it, as, for example the sockedDidDisconnect delegate does not have the tag that the timeout refers to (I ended up tracking it myself as part of this "hacky" way), so it does not seem like the natural way to handle possible failures of specific commands.

What am I missing? How do you "test" a command to see if it gives you a response or not, in order to proceed based on that knowledge?

Upvotes: 1

Views: 58

Answers (0)

Related Questions