SRWebsocket close the connection ios - ios

I am using SRWebsocket in my connection class I am trying to disconnect the socket when the app goes to background i have tried these things
SRWebSocket *_webSocket;
-(void)close
{
[_webSocket close];
_webSocket.delegate = nil;
_webSocket = nil;
}
but it is not closing the socket please help me in doing so .

Keep in mind that, if you nil the websocket delegate at this point, when the socket actually closes (it's not inmediate), there will be no delegate to process the webSocket:diCloseWithCode: event. But the socket should certainly be closed anyway.
It may not be that, but it would make more sense to just send the close message. Then wait for the didClose and there, you can nil both the delegate and the actual _websocket.

Related

Catching the Parse kPFErrorConnectionFailed error-code & Cancelling the pullToRefresh’s UIActivityIndicatorView in the IOS PFQueryTableViewController

I have two questions as follows:
I will like to catch the kPFErrorConnectionFailed error-code from the query in the IOS PFQueryTableViewController’s queryForTable. How do I go about it?
After the last attempt to connect to Network and I receive [Error]: Network connection failed, How do I cancel the pullToRefresh’s UIActivityIndicatorView which currently continues to load indefinitely?
What I’ve tried:
Concerning catching error-code kPFErrorConnectionFailed, I tried the following (which does not catch the error):
- (void)objectsDidLoad:(NSError *)error {
[super objectsDidLoad:error];
if(error.code == kPFErrorConnectionFailed)
{…}
}
A work around for Catching kPFErrorConnectionFailed is to use Apple's Reachability Class to check if the Parse Network Server is reachable before trying to load data.
A fix to the indefinite pullToRefresh UIActivityIndicatorView is to use kPFCachePolicyCacheThenNetwork as opposed to the kPFCachePolicyNetworkOnly. The kPFCachePolicyNetworkOnly keeps trying to load data from the network even with a bad connection. However, kPFCachePolicyCacheThenNetwork relies on the cached data when the network server is unreachable. Check here for more information

GCDAsyncSocket readDataWithTimeout is not continuing to read data

I am using GCDasyncsocket in my iOS app to send a string over a socket connection and then to read a string every second over the same socket connection. I am also creating a second socket to the same server on a different port ad reading once a second there as well.
My write is working properly and the first few reads on each socket work properly, but then the connection appears to stop.
My current method of reading every second is to kick off the reads by calling
[asyncSocket readDataWithTimeout:1 tag:1];
[asyncSocket_Emove readDataWithTimeout:1 tag:2];
at the end of "didConnectToHost" and the similarly calling them again at the end of "didReadDatawithTag"
I can provide more details if needed, but does anyone have an idea why the socket is stopping?
Replace this line
[asyncSocket readDataWithTimeout:1 tag:1];
with this
[asyncSocket readDataWithTimeout:-1 tag:1];
may work for you.

Cancelling XPC connection in -dealloc when cancellation handler references self

In my project I am using the C-based XPC API, since NSXPCConnection is not available on the platform I am targeting. Currently I use a weak reference to prevent the connection handler block from retaining self, as follows:
__block VTVoltControllerProxy *proxy = self;
xpc_connection_set_event_handler(_connection, ^(xpc_object_t object) {
xpc_type_t type = xpc_get_type(object);
...
if (type == XPC_TYPE_ERROR && object == XPC_ERROR_CONNECTION_INVALID) {
if ([[proxy delegate] respondsToSelector:#selector(voltControllerDidDisconnectFromHost:)]) {
[[proxy delegate] voltControllerDidDisconnectFromHost:proxy];
}
}
});
However, an issue is introduced whenever the connection is cancelled inside the -dealloc method of my class:
- (void)dealloc
{
...
xpc_connection_cancel(_connection);
xpc_release(_connection);
...
}
Because cancelling an XPC connection is an asynchronous operation, the connection handler is called after the class instance has already been deallocated, causing proxy to point to an object that no longer exists.
Is there a way that I can safely cancel the connection in -dealloc and have the connection handler call the delegate method after cancellation?
You should be able to change the event handler to point at an event handler which is only used for the purpose of watching that the connection closes. You can either queue the pending connections in another object (perhaps a global or static) or just make the assumption that any connection calling this separate event handler is being called because it is being cancelled (check the event type of course).
Running into the same problem today. I don't know if you already resolved this or not. But what if dealloc waits for the XPC connection to be closed before continue.
It's possible to introduce a conditional variable to achieve this behavior.
But I am wondering what the drawback it could bring.

Difference between cancelling a connection and setting it to nil

In iOS I am using NSURLConnection -
NSURLConnection *aConnection = [[NSURLConnection alloc....
is there a difference between:
[aConnection cancel];
and
aConnection = nil;
Thanks
When you send the connection a cancel message, it will stop to invoke your delegates as soon as possible and tear down the connection.
Note: it may happen in rare cases that you still get one already queued delegate message other than connection:didFailWithError: after you send cancel from a different tread than the one the connection schedules delegates.
With setting your reference to the connection to nil, you simply do this. This does not cancel the connection - and if this was your only reference, you also can't send a cancel anymore. ;)
Basically by doing this:
aConnection = nil;
you cannot be sure that there are no other references to this object. So you should do this:
[aConnection cancel];

"Connection reset by peer" errors with GCDAsyncUdpSocket on iOS6

I am having a problem with using GCDAsyncUdpSocket. I am using the iPad as a user interface app that interacts with another app - call it Host, the latter running on a separate Windows machine. Both machines are on their own private network, so they are on their own subnet. At certain points, the Host sends UDP packets to the iPad to instruct it which screen to show to the user, and the iPad sends user responses via UDP packets to the Host. Finally, the iPad periodically (at 2 Hz) sends simple "heartbeat" messages to the Host.
This all works fine - for a while. Then, apparently, the iPad abruptly stops accepting the UDP packets from the Host - the latter experiences "Connection reset by peer" errors, while it (the iPad) is still successfully sending, and the Host receiving, the heartbeat messages.
I'm thinking the problem comes from my confusion with respect to how Grand Central Dispatch (GCD) works. My iPad app is pretty simple; I based it off a tutorial on iOS programming (I'm a beginner here, but very experienced with Windows, Linux, embedded/real-time, and networking). It basically consists of a main screen, which creates a second screen from time to time. So the basic structure is this:
main.m
Delegate.m
MainViewController.m
PopupViewController.m
The main.m and Delegate.m were created automagically by the Xcode during the tutorial, and have nothing special in them. The MainViewController.m is my "main screen", and owns the GCDAsyncUdpSocket that is used by the iPad app. The final file, PopupViewController.m, is the second screen, that is used like this:
# MainViewController.m
- (IBAction)sendResponseOne:(id)sender {
// Send a message to Host
[self sendUdpMessage:1];
// Switch to other view
PopupViewController *vc = [[PopupViewController alloc] init];
[vc setMainScreen:self]; // Used to access UDP from 2nd screen
[self presentViewController:vc animated:NO completion:nil];
}
# PopupViewController.m
- (IBAction)confirmAnswers:(id)sender
{
// Send a message to Host - calls same function as above main screen
[self->mainScr sendUdpMessage:2];
[self dismissViewControllerAnimated:NO completion:nil];
}
Now for the code that sems to fail. First, here is the #interface section of MainViewController.m:
# From MainViewController.m
#interface MainViewController ()
{
GCDAsyncUdpSocket *udpSocket;
}
#end
Here is how/where I create the UDP object:
# From MainViewController.m
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]))
{
// Setup our socket, using the main dispatch queue
udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
}
return self;
}
Here is where I bind to the port:
# From MainViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Start UDP server
int port = 12349;
NSError *error = nil;
if (![udpSocket bindToPort:port error:&error])
{
NSLog(#"Error starting server (bind): %#", error);
return;
}
if (![udpSocket beginReceiving:&error])
{
[udpSocket close];
NSLog(#"Error starting server (recv): %#", error);
return;
}
[self startPingTimer];
isRunning = YES;
}
Here's the code that receives packets. Apparently, this function works fine for awhile, sometimes dozens of times, then unexpectedly fails.
# From MainViewController.m
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext
{
if (data.length == sizeof(MyMessage)) {
MyMessage msg;
[data getBytes:&msg length:sizeof(MyMessage)];
msg.magic = ntohl(msg.magic);
msg.msgId = ntohl(msg.msgId);
for (int i = 0; i < 4; ++i) {
msg.values[i] = ntohl(msg.values[i]);
}
if (msg.magic == 0xdeadcafe) {
switch (msg.msgId) {
case imiStateControl:
self->iceState = (IceState)msg.values[0];
break;
default:
break;
}
}
}
}
I am at a loss as to why the didReceiveData function seems to work correctly for some random amount of time (and random number of messages sent/received). I wonder a couple of things:
Is it valid for me to send a UDP message from the second screen? I think so, and sending never fails - it continues to work even after receiving fails.
How does the didReceiveData get called anyway, and how could that get broken? If I was in Linux or an RTOS, I would probably have created an explicit thread that waits on packets; how does the GCD framework decide where a packet should go?
Why would my app suddenly stop listening on the port? How do I detect/debug that?
Does it matter that the GCDAsyncUdpSocket object is owned by the main screen, as opposed to the Delegate.m module?
Is it appropriate to use the main dispatch queue, as I think I am doing? Indeed, am I doing that, and correctly?
I'm totally at a loss, so of course, any advice would be greatly appreaciated! No need to answer all the questions - especially if your answer to one is the solution!
Thanks!
This post ended about eight hours of torture that I received at the hands of the POSIX/GCDAsyncSocket/NSStream/NSNetService gods. For anyone coming across this: the cause of my GCDAsyncSocket connection reset by peer/remote peer disconnected errors was simply that I was connecting by IP on the LAN, instead of using a host name. (i.e. using the connectToAddress family of methods instead of the connectToHost family of methods). I fired up WireShark, downloaded X11, all that jazz and confirmed I was facing the same issue Bob was seeing – ARP activity around the disconnect time. Trying to connect to a host instead of an address confirmed Seth's take on the situation – it was issues with the router reassigning IP addresses.
This couldn't have been a more innocuous question on SO – question and answer with 0 upvotes, but both of you combined to give more more than enough information to solve what I thought was an intractable problem. Thanks so much!
It sounds like the receiving UDP socket is either being closed or shifted to a different address/port pair.
If its being closed, the only way outgoing packets could still work is if there were actually two sockets. Perhaps the receive one bound to port 12349 and the send one bound to port 0. Then maybe GCD is closing the receive one after some period of time. Given your followup comments about ARP, this seems less likely but is worth keeping in mind.
The ARP activity suggests that the iPad's IP address may be changing. If it were to change, or if it were to switch from the WiFi interface to a cellular interface, then the packets it sends would still get through, but packets sent to it would fail exactly as described.
Whatever is receiving those heart-beat messages, have it check the recvfrom address and make sure that any messages it sends back go to that exact address. And, of course, make sure to pay attention to endian (host vs network byte order).
I am assuming that there are no firewalls or NAT in between the two devices. If there are such things, then a whole different world of possibilities opens up.

Resources