why GCDAsyncUdpSocket cannot send/receive packets after a while in broadcast mode? - ios

I am using GCDAsyncUdpSocket to write a UDP socket in my app. The scenario is like this: when users click the button, it will send a broadcast packet in LAN then listen to the response, there is a server in LAN which will respond with one UDP packet. When the app receives the response, it will do something.
I set GCDAsyncUdpSocket as followings:
- (void)setupSocket
{
_udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
if (![_udpSocket bindToPort:18686 error:&error]) {
NSLog(#"Error binding: %#",error);
return;
}
if (![_udpSocket beginReceiving:&error]) {
NSLog(#"Error receiving: %#",error);
return;
}
if (![_udpSocket enableBroadcast:YES error:&error]) {
NSLog(#"Error enableBroadcast: %#",error);
return;
}
}
then i send Packet in button action as following:
NSString *host = #"255.255.255.255";
int port = 8585;
NSString *msg = #"Hello from iOS";
NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
[_udpSocket sendData:data toHost:host port:port withTimeout:-1 tag:0];
in
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext
method i listen the port to do somethings. It works perfectly at beginning, but if you try to click the button later (about 1 hour), then it cannot send UDP packet any more.
My server in LAN will print the data received. I thought there was something wrong with send method. so i use BSD socket methods to send The data. and use GCDAsyncUdpSocket to receive the response. but the same thing happened after a while. this time i can send but cannot receive.
Am i missing something about GCDAsyncUdpSocket? why it cannot send/receive after a while? Any help would be much appreciated.

It may be some timeout setting. Implement the GCDAsyncUdpSocketDelegate protocol to fetch detailed information about what is going on.
The hard solution is to establish a new connection.

Related

Can you setup listener socket on localhost with iOS?

I'm trying to setup a listenerSocket on localhost using GCDAsyncSocket for iOS device.
In the socketDidDisconnect delegate I either get error Code=49 for trying with port 0 (which I'm hoping would find the first available free port).
Or if I use a port no then I get error Code=61 for trying to connect with localhost.
- (IBAction)start:(id)sender {
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *err = nil;
if(![asyncSocket connectToHost:#"localhost" onPort:0 error:&err])
{
NSLog(#"Connect Error: %#", err);
}
}
#pragma mark – delegate
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
NSLog(#"socketDidDisconnect");
if (err) {
NSLog(#"Socket Error: %#", err);
// Error in connect function:
// NSPOSIXErrorDomain Code=49 "Can't assign requested address" - onPort:0
// NSPOSIXErrorDomain Code=61 "Connection refused" - connectToHost:#"localhost"
}
}
connectToHost will act as the client-side of the connection. You want to read the Writing a server section of the help page:
listenSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
if (![listenSocket acceptOnPort:port error:&error])
{
NSLog(#"I goofed: %#", error);
}
- (void)socket:(GCDAsyncSocket *)sender didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
// The "sender" parameter is the listenSocket we created.
// The "newSocket" is a new instance of GCDAsyncSocket.
// It represents the accepted incoming client connection.
// Do server stuff with newSocket...
}
However you need to know the port to use (if you let the system decide what port to use then how is a client supposed to know how to connect to the server?). Also the port will almost certainly need to be > 1024 (out of the reserved port range). However I haven't ever tried to create a Server on iOS.

ios Read data at fast rate in UDP

i am establishing a UDP connection using GCDAsyncSocket(ios device). Everything working fine and im able to send and receive messages, my problem is that i want to exchange data fast. I can send pretty fast data from my iphone to a pc but i cant get at that speed data from pc, more specific i want to be able to get data every 100ms.
I use this function when i connect successfully:
-(void)startRead {
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(startRead) userInfo:nil repeats:YES];
[asyncSocket readDataWithTimeout:-1 tag:0];
}
With this i can read data with 1sec interval but if i try to put 0.1 seconds my program freezes.(Same with values under 1second) Im sure that im doing something wrong here and there will be a way to achieve what i want so if anybody know plz help!!
thanx
I believe the above comment is correct, you've not set the Delegate correctly on init. The socket creation should be something like this
GCDAsyncUdpSocket* udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
if (![udpSocket bindToPort:0 error:&error])
{
[self logError:[NSString stringWithFormat:#"Error binding: %#", error]];
return;
}
if (![udpSocket beginReceiving:&error])
{
[self logError:[NSString stringWithFormat:#"Error receiving: %#", error]];
return;
}
NSString *_host = nil;
uint16_t _port = 0;
[GCDAsyncUdpSocket getHost:&_host port:&_port fromAddress:udpSocket.localAddress];
[self logInfo:[NSString stringWithFormat:#"Socket setup on host %#:%d", _host, _port]];
[self logInfo:#"Socket created successfully."];
Unless you're using a different version of GCDAsyncUdpSocket than I'm familiar with, the correct callback method is actually the below method. This is called automatically when the delegate is set and a packet is received on the correct port.
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext

Node JS udp broadcast not read -- node js and iOS

here is my code (javascript for node):
var dgram = require('dgram');
var message = new Buffer("why hello beautiful");
var client = dgram.createSocket("udp4");
client.bind(41234);
client.setBroadcast(true);
client.send(message, 0, message.length, 41234, "134.71.147.255");
console.log('msg sent');
client.close();
here is the ifconfig for my computer running node (the only pertinent thing I think -- correct me if im wrong please):
inet addr:134.71.146.49 Bcast:134.71.147.255 Mask:255.255.254.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
The udp broacast is neither recieved on my iOS app nor visible through a packet inspector.
What is going wrong?! The iOS app uses the GCDAsyncUdpSocket framework:
- (void) initUDPlistener {
NSLog(#"initUDPlistener");
udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
if (![udpSocket bindToPort:UDP_PORT error:&error]) //does the port matter? i dont know
{
return;
}
if (![udpSocket beginReceiving:&error])
{
return;
}
[udpSocket enableBroadcast:YES error:nil];
[udpSocket sendData:[self pack:#"iOS to bcast"] toHost:UDP_BCAST_ADDR port:UDP_PORT withTimeout:-1 tag:0];
}
#pragma mark -
#pragma mark Delegate UDP methods
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext
{
NSLog(#"niets.");
NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (msg)
{
NSLog(#"iets gekregen");
}
else
{
NSLog(#"Error convertion");
}
NSLog(#"HMMMM");
}
-(void) udpSocket:(GCDAsyncUdpSocket *) sock didSendDataWithTag:(long)tag {//called. and packet inspector recieves the packet when it is sent OUT from the iOS app.
NSLog(#"written data tag: %ld", tag);
}
-(void) udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address { //never called
NSLog(#"connected to some address");
}
What happens:
"didReceiveData" does not get called from the node broadcast. It gets called when it sends its own message out, however.
the iOS app, on the other hand, successfully broadcasts and i am able to intercept that packet on my packet inspector. The same packet inspector does not show packets that should be originating from Node, however.
what am I doing wrong in node? I think what I am doing in node is the problem.

sending UDP request to 255.255.255.255 and waiting for reply in iOS

Im would to send a UDP broadcast from an iPhone, and then listen for a UDP response with a timeout period from all devices with such port opened. Does my custom device from the same subnet would answer? ( if mine is 192.168.1.100 and IP of custom device is 192.168.1.201 )
What to use "SmallSockets" or "cocoaAsyncSocket" ?
What function to use to listen for response?
Thanx!
i decided to use cocoaAsyncSocket.
To broadcast you can use:
[udpSocket sendData:datatosend toHost:#"192.168.1.113" port:port withTimeout:-1 tag:0];
to receive:
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext
{
NSString *msg = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
NSString *host = nil;
uint16_t port = 0;
[GCDAsyncUdpSocket getHost:&host port:&port fromAddress:address];
if (msg)
{
NSLog(#"Message = %#, Adress = %# %i",msg,host,port);
}
else
{
NSLog(#"Error converting received data into UTF-8 String");
}
}

iPad GCDAsyncSocket doesn't read

I really need some help with my project...
I need to exchange data with my server written in Java. I tried using GCDAsyncSocket, and I can send message to server, read it on server, but when server sends response to client, I can't (don't know how to) read it on client. Here is part of my code:
- (void) someMethod{
NSError *err = nil;
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
if(![asyncSocket connectToHost:#"localhost" onPort:7777 error:&err]){
// If there was an error, it's likely something like "already connected" or "no delegate set"
NSLog(#"I goofed: %#", err);
}
NSString *requestStr = #"<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><root><service>1</service><type>1</type><userProperties><username>ivo</username></userProperties></root>";
NSData *requestData = [requestStr dataUsingEncoding:NSUTF8StringEncoding];
[asyncSocket writeData:requestData withTimeout:-1.0 tag:0];
[asyncSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:1.0 tag:0];
[asyncSocket disconnectAfterWriting];
}
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
if (tag == 0)
NSLog(#"First request sent");
else if (tag == 2)
NSLog(#"Second request sent");
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#",str);
}
Please help, if there is another way I am willing to try as I am getting desperate...
I see that you're sending XML, with no particular terminator at the end of your request data, yet you're expecting the server to send a response terminated by a \r\n?
What does the protocol specify?
Sending and receiving data over tcp is a common cause of confusion because tcp is stream based. It has no concept of individual reads/writes. It treats all data as conceptually a never ending stream. The protocol dictates message boundaries. For a better explanation, see the "Common Pitfalls" article from GCDAsyncSocket's wiki:
https://github.com/robbiehanson/CocoaAsyncSocket/wiki/CommonPitfalls
I think it will help explain a lot.

Resources