04-19-2009, 10:41 AM
#1 (permalink )
Registered Member
Join Date: Oct 2008
Posts: 97
Alternative to NSURLConnection?
My application is internet based. It queries a custom .php script to display it's data. I implemented NSURLConnection into a class of it's own to deal with my error correcting protocol. This class sends a message back to the delegate with success for fail. It works great but it has a memory leak. I've read all over that this memory leak in CFNetwork / httpWrFilterOpen is a bug in iPhone's operating system. Since my application has many screens that each requires the internet, it has a potential for a lot of leaks and I'm not okay with that.
Can I use AsyncSocket as a replacement for simple HTTP GET commands? Or are there any alternatives that do the same thing without using NSURLConnection?
Thanks!
Chris
04-19-2009, 04:31 PM
#2 (permalink )
Former NeXTStep Developer
Join Date: Mar 2009
Posts: 997
Quote:
Originally Posted by
fordracerguy
Can I use AsyncSocket as a replacement for simple HTTP GET commands? Or are there any alternatives that do the same thing without using NSURLConnection?
Thanks!
Chris
I have an application that uses ASyncSocket to talk to a device over the network. In my case, it's talking to a telnet server on the device, rather than an http server. It'll work, but it's much effort to get it all set up properly.
joe
04-20-2009, 05:13 PM
#3 (permalink )
Registered Member
Join Date: Oct 2008
Posts: 97
Quote:
Originally Posted by
FlyingDiver
I have an application that uses ASyncSocket to talk to a device over the network. In my case, it's talking to a telnet server on the device, rather than an http server. It'll work, but it's much effort to get it all set up properly.
joe
Would you mind sharing a bit of code on how you implemented it?
04-20-2009, 05:22 PM
#4 (permalink )
Former NeXTStep Developer
Join Date: Mar 2009
Posts: 997
Quote:
Originally Posted by
fordracerguy
Would you mind sharing a bit of code on how you implemented it?
The docs that come with the class files are actually pretty good. All my code was based on queuing multiple telnet commands to go to the server device. I don't think it would help you much. The real trick is deciding how you want to handle the asynchronicity of the interactions in your application.
Heck, here's about 95% of the code that uses the AsyncSocket class. If it helps, great.
Code:
#import <Foundation/Foundation.h>
#import <CoreFoundation/CFStream.h>
#import "AsyncSocket.h"
#include <fcntl.h>
#include <unistd.h>
@interface Controller : NSObject {
NSMutableArray *cmdQueue;
AsyncSocket *socket;
int writesPending;
long writeNum, readNum;
BOOL connectionReady;
}
@property (readonly) NSMutableArray *cmdQueue;
@property (readonly) BOOL connectionReady;
-(id)initWithControllerIP:(NSString *) ipAddress;
-(void)getValue:(NSString *) name;
-(void)setValue:(NSString *) value forName: (NSString *) name;
-(void)sendCommand: (NSString *) cmd;
-(void)kickQueue;
-(void)onSocket:(AsyncSocket *) sock willDisconnectWithError:(NSError *) err;
-(void)onSocketDidDisconnect:(AsyncSocket *) sock;
-(void)onSocket:(AsyncSocket *) sock didConnectToHost:(NSString *) host port:(UInt16) port;
-(void)onSocket:(AsyncSocket *) sock didReadData:(NSData*) data withTag:(long) t;
-(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag;
@end
Code:
- (id)initWithControllerIP:(NSString *)ipAddress
{
// create queue for commands to send to controller
if (!(cmdQueue = [[NSMutableArray alloc] init]))
NSLog(@"Error creating Queue");
writesPending = 0;
connectionReady = NO;
int port = 23; // telnet port
if (!(self = [super init]))
return nil;
// Create socket.
socket = [[AsyncSocket alloc] initWithDelegate:self];
// Set up stdin for non-blocking.
if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
{
NSLog (@"Can't make STDIN non-blocking.");
exit(1);
}
@try
{
NSError *err;
if ([socket connectToHost:ipAddress onPort:port error:&err])
{
NSLog (@"Attempting connection to %@:%u.", ipAddress, port);
}
else
{
NSLog (@"Couldn't connect to %@:%u (%@).", ipAddress, port, err);
return nil;
}
}
@catch (NSException *exception)
{
NSLog ([exception reason]);
return nil;
}
return self;
}
#pragma mark -
#pragma mark AsyncSocketDelegate methods
-(void) onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
if (err != nil)
NSLog (@"Socket will disconnect. Error domain %@, code %d (%@).",
[err domain], [err code], [err localizedDescription]);
else
NSLog (@"Socket will disconnect. No error.");
connectionReady = NO;
}
-(void) onSocketDidDisconnect:(AsyncSocket *)sock
{
NSLog (@"Socket disconnected.");
connectionReady = NO;
[[NSNotificationCenter defaultCenter] postNotificationName: @"iDSC_Disconnect" object: self userInfo: nil];
}
-(void) onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port;
{
NSLog (@"Socket connected to %@:%u.", host, port);
connectionReady = YES; // can't use the controller until this is set
NSData *newline = [@"\n" dataUsingEncoding:NSASCIIStringEncoding];
[socket readDataToData:newline withTimeout:-1 tag: 0]; // clear any garbage from the connection, start reads
}
-(void) onSocket:(AsyncSocket *)sock didReadData:(NSData*)data withTag:(long)tag
{
NSString *serverReply = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
// look at reply, and if it's a getvalue response ( name = "value"), post a Notification
if ([serverReply rangeOfString:@"="].location != NSNotFound)
{
NSString *replyName = nil;
NSString *replyValue = nil;
NSScanner *scanner = [NSScanner scannerWithString:serverReply];
// discard the device prompt
[scanner scanUpToString:@"%" intoString:nil];
[scanner scanUpToString:@" " intoString:nil];
[scanner scanString:@" " intoString:nil];
// first string (up to space) is the variable name
[scanner scanUpToString:@" " intoString:&replyName];
// skip = and first "
[scanner scanUpToString:@"=" intoString:nil];
[scanner scanUpToString:@"\"" intoString:nil];
[scanner scanString:@"\"" intoString:nil];
// up to next quote is value
[scanner scanUpToString:@"\"" intoString:&replyValue];
// if we got valid data, post it
if (replyName && replyValue) {
NSDictionary *update = [NSDictionary dictionaryWithObject:replyValue forKey:replyName];
[[NSNotificationCenter defaultCenter] postNotificationName: @"iDSC_Update" object: self userInfo: update];
}
}
[serverReply release];
NSData *newline = [@"\n" dataUsingEncoding:NSASCIIStringEncoding];
[socket readDataToData:newline withTimeout:-1 tag: 0];
}
// Whenever a write completes, decrement the count of writes outstanding, and kick the queue to see if there are more to send
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
writesPending--;
[self kickQueue];
}
- (void) kickQueue
{
// NSLog(@"kickQueue, writesPending = %d, cmdQueue count = %d", writesPending, [cmdQueue count]);
while ((writesPending < 3) && ([cmdQueue count] > 0))
{
NSString *request = [cmdQueue objectAtIndex:0];
NSData *data = [request dataUsingEncoding:NSASCIIStringEncoding];
[socket writeData:data withTimeout:-1 tag: 0];
[cmdQueue removeObjectAtIndex:0];
writesPending++;
}
}
04-20-2009, 05:44 PM
#5 (permalink )
Registered Member
Join Date: Mar 2009
Posts: 122
Apparently
Code:
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
has stopped NSURLConnection leaking for some people.
I have yet to try it on my own leaking NSURLConnection.
I assume you just insert the snippet before your call,
but I may be very wrong.
04-20-2009, 05:48 PM
#6 (permalink )
Registered Member
Join Date: Oct 2008
Posts: 97
Quote:
Originally Posted by
m0s
Apparently
Code:
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
has stopped NSURLConnection leaking for some people.
I have yet to try it on my own leaking NSURLConnection.
I assume you just insert the snippet before your call,
but I may be very wrong.
I've tried these with no luck. It may have to do with the cache policy. I was just over on the devforums and some apple engineers said if it doesn't happen every connection, which it doesn't, don't worry about it. I guess it's fixed for good in the next OS.
04-20-2009, 06:46 PM
#7 (permalink )
Registered Member
Join Date: Oct 2008
Posts: 97
Quote:
Originally Posted by
FlyingDiver
The docs that come with the class files are actually pretty good. All my code was based on queuing multiple telnet commands to go to the server device. I don't think it would help you much. The real trick is deciding how you want to handle the asynchronicity of the interactions in your application.
Heck, here's about 95% of the code that uses the AsyncSocket class. If it helps, great.
Thanks!! Very nice code indeed. I was just over at the apple devforums and there are numerous postings of my issue. Apple employees even said in more or less words to just ignore it for now, I guess it's fixed in the next OS...
09-03-2009, 12:46 AM
#8 (permalink )
Registered Member
Join Date: Jul 2009
Location: India
Posts: 78
Hi FlyingDiver, need little clarification...you have called the read data function using
Code:
[socket readDataToData:newline withTimeout:-1 tag: 0]; // clear any garbage from the connection, start reads
In my app, i need to write a data to the server, i have added the following code
Code:
-(void) onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port;{
NSLog (@"Socket connected to %@:%u.", host, port);
btnRecord.enabled=TRUE;
connectionReady = YES; // can't use the controller until this is set
bytes=[NSData dataWithBytes:buf length:size];
[socket writeData:bytes withTimeout:-1 tag: 0];
}
}
is that correct? bcause i tried above code and the server doesnt receive any data.
is there any other way?
thanks,
sumanth
12-27-2010, 06:23 AM
#9 (permalink )
Registered Member
Join Date: Dec 2010
Posts: 2
iPhone App to send commands to telnet server
Hello FlyingDriver,
Can you please send me the complete code as there is no implementation of sendCommand and readResponse methods.
Please respond quickly because I have deadline....
Quote:
Originally Posted by
FlyingDiver
The docs that come with the class files are actually pretty good. All my code was based on queuing multiple telnet commands to go to the server device. I don't think it would help you much. The real trick is deciding how you want to handle the asynchronicity of the interactions in your application.
Heck, here's about 95% of the code that uses the AsyncSocket class. If it helps, great.
Code:
#import <Foundation/Foundation.h>
#import <CoreFoundation/CFStream.h>
#import "AsyncSocket.h"
#include <fcntl.h>
#include <unistd.h>
@interface Controller : NSObject {
NSMutableArray *cmdQueue;
AsyncSocket *socket;
int writesPending;
long writeNum, readNum;
BOOL connectionReady;
}
@property (readonly) NSMutableArray *cmdQueue;
@property (readonly) BOOL connectionReady;
-(id)initWithControllerIP:(NSString *) ipAddress;
-(void)getValue:(NSString *) name;
-(void)setValue:(NSString *) value forName: (NSString *) name;
-(void)sendCommand: (NSString *) cmd;
-(void)kickQueue;
-(void)onSocket:(AsyncSocket *) sock willDisconnectWithError:(NSError *) err;
-(void)onSocketDidDisconnect:(AsyncSocket *) sock;
-(void)onSocket:(AsyncSocket *) sock didConnectToHost:(NSString *) host port:(UInt16) port;
-(void)onSocket:(AsyncSocket *) sock didReadData:(NSData*) data withTag:(long) t;
-(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag;
@end
Code:
- (id)initWithControllerIP:(NSString *)ipAddress
{
// create queue for commands to send to controller
if (!(cmdQueue = [[NSMutableArray alloc] init]))
NSLog(@"Error creating Queue");
writesPending = 0;
connectionReady = NO;
int port = 23; // telnet port
if (!(self = [super init]))
return nil;
// Create socket.
socket = [[AsyncSocket alloc] initWithDelegate:self];
// Set up stdin for non-blocking.
if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
{
NSLog (@"Can't make STDIN non-blocking.");
exit(1);
}
@try
{
NSError *err;
if ([socket connectToHost:ipAddress onPort:port error:&err])
{
NSLog (@"Attempting connection to %@:%u.", ipAddress, port);
}
else
{
NSLog (@"Couldn't connect to %@:%u (%@).", ipAddress, port, err);
return nil;
}
}
@catch (NSException *exception)
{
NSLog ([exception reason]);
return nil;
}
return self;
}
#pragma mark -
#pragma mark AsyncSocketDelegate methods
-(void) onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
if (err != nil)
NSLog (@"Socket will disconnect. Error domain %@, code %d (%@).",
[err domain], [err code], [err localizedDescription]);
else
NSLog (@"Socket will disconnect. No error.");
connectionReady = NO;
}
-(void) onSocketDidDisconnect:(AsyncSocket *)sock
{
NSLog (@"Socket disconnected.");
connectionReady = NO;
[[NSNotificationCenter defaultCenter] postNotificationName: @"iDSC_Disconnect" object: self userInfo: nil];
}
-(void) onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port;
{
NSLog (@"Socket connected to %@:%u.", host, port);
connectionReady = YES; // can't use the controller until this is set
NSData *newline = [@"\n" dataUsingEncoding:NSASCIIStringEncoding];
[socket readDataToData:newline withTimeout:-1 tag: 0]; // clear any garbage from the connection, start reads
}
-(void) onSocket:(AsyncSocket *)sock didReadData:(NSData*)data withTag:(long)tag
{
NSString *serverReply = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
// look at reply, and if it's a getvalue response ( name = "value"), post a Notification
if ([serverReply rangeOfString:@"="].location != NSNotFound)
{
NSString *replyName = nil;
NSString *replyValue = nil;
NSScanner *scanner = [NSScanner scannerWithString:serverReply];
// discard the device prompt
[scanner scanUpToString:@"%" intoString:nil];
[scanner scanUpToString:@" " intoString:nil];
[scanner scanString:@" " intoString:nil];
// first string (up to space) is the variable name
[scanner scanUpToString:@" " intoString:&replyName];
// skip = and first "
[scanner scanUpToString:@"=" intoString:nil];
[scanner scanUpToString:@"\"" intoString:nil];
[scanner scanString:@"\"" intoString:nil];
// up to next quote is value
[scanner scanUpToString:@"\"" intoString:&replyValue];
// if we got valid data, post it
if (replyName && replyValue) {
NSDictionary *update = [NSDictionary dictionaryWithObject:replyValue forKey:replyName];
[[NSNotificationCenter defaultCenter] postNotificationName: @"iDSC_Update" object: self userInfo: update];
}
}
[serverReply release];
NSData *newline = [@"\n" dataUsingEncoding:NSASCIIStringEncoding];
[socket readDataToData:newline withTimeout:-1 tag: 0];
}
// Whenever a write completes, decrement the count of writes outstanding, and kick the queue to see if there are more to send
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
writesPending--;
[self kickQueue];
}
- (void) kickQueue
{
// NSLog(@"kickQueue, writesPending = %d, cmdQueue count = %d", writesPending, [cmdQueue count]);
while ((writesPending < 3) && ([cmdQueue count] > 0))
{
NSString *request = [cmdQueue objectAtIndex:0];
NSData *data = [request dataUsingEncoding:NSASCIIStringEncoding];
[socket writeData:data withTimeout:-1 tag: 0];
[cmdQueue removeObjectAtIndex:0];
writesPending++;
}
}
Last edited by madni.abbasi; 01-11-2011 at 03:05 PM .
01-12-2011, 08:11 AM
#10 (permalink )
Registered Member
Join Date: Dec 2010
Posts: 2
Hi All,
Is there anybody who have working application sending command to telnet server ?
I need little clarification if possible.
Thread Tools
Display Modes
Linear Mode
Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
» Advertisements
» Stats
Members: 175,649
Threads: 94,113
Posts: 402,880
Top Poster: BrianSlick (7,990)
Welcome to our newest member, Anwerbl