SSDP on the iPhone - iphone

I need to be able to send out a UDP message and also receive one in order to discover SSDP devices on the network from the iPhone.
I know that I need to send the packet to the multicast address and my HTTP request needs to look something like this:
M-SEARCH * HTTP/1.1
Host: 239.255.255.250:1900
Man: ssdp:discover
Mx: 3
ST: "urn:schemas-upnp-org:device:InternetGatewayDevice:1"
From reading the docs it appears that I can do all this with CFNetwork and despite reading (and re-reading the docs) I am struggling to get started. Can anyone recommend and tutorials or code snippets to get me over the initial learning hump?
I've got the CFNetwork programming guide:
http://developer.apple.com/mac/library/documentation/Networking/Conceptual/CFNetwork/CFNetwork.pdf
and Beej's Guide to Network programming Using Internet Sockets:
http://beej.us/guide/bgnet/
Thanks
Dave
P.S.
I am unable to use any of the 3rd party libraries and frameworks in this instance.

I have used AsyncUdpSocket successfully to run SSDP Discovery and find controllers. Here are my code snippets:
Initialize and setup the socket:
// AsyncUdpSocket *ssdpSock = [[AsyncUdpSocket alloc] initWithDelegate:self];
AsyncUdpSocket *ssdpSock = [[AsyncUdpSocket alloc] initIPv4];
[ssdpSock setDelegate:self];
Note the first line commented out. I found on the AsyncUdpSocket forums some issues with duplicates. I don't think I was facing them but I did it anyhow.
I added error checking, and it was useful because during my debugging I wasn't closing sockets and I started getting socket setup failures:
NSError *socketError = nil;
if (![ssdpSock bindToPort:1900 error:&socketError]) {
NSLog(#"Failed binding socket: %#", [socketError localizedDescription]);
return statusController;
}
if(![ssdpSock joinMulticastGroup:#"239.255.255.250" error:&socketError]){
NSLog(#"Failed joining multicast group: %#", [socketError localizedDescription]);
return statusController;
}
if (![ssdpSock enableBroadcast:TRUE error:&socketError]){
NSLog(#"Failed enabling broadcast: %#", [socketError localizedDescription]);
return statusController;
}
[ssdpSock sendData:[self.discoverControllerString dataUsingEncoding:NSUTF8StringEncoding]
toHost:#"239.255.255.250"
port:1900
withTimeout:2
tag:1];
Notice the changes I have made to the time out. And then finally did the receive setup, and closed the socket. Note the socket close. Since I am in my own class when I am running this - the code above did not work for me.
[ssdpSock receiveWithTimeout: 2 tag:1];
[NSTimer scheduledTimerWithTimeInterval: 5 target: self
selector:#selector(completeSearch:) userInfo: self repeats: NO];
[ssdpSock closeAfterSendingAndReceiving];
The most important change probably was returning "NO" if I did not find my controller. The first receive was incidentally the discovery message itself coming back. And when I read through the AsyncUdpSocket.h file carefully - returning "NO" when it is not a packet you are looking for helped.
Also note that I am using ARC in my code but I compiled the AsyncUdpSocket without ARC support.
-(void) completeSearch: (NSTimer *)t
{
NSLog(#"%s",__FUNCTION__);
//[ssdpSock close];
//ssdpSock = nil;
}
- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock
didReceiveData:(NSData *)data
withTag:(long)tag
fromHost:(NSString *)host
port:(UInt16)port
{
NSLog(#"%s %ld %# %d",__FUNCTION__,tag,host,port);
NSString *aStr = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"%#",aStr);
NSString *compareString = [aStr stringByPaddingToLength:[self.responseString length] withString:#"." startingAtIndex:0];
//NSLog(#"%#", compareString);
//NSLog(#"%#", self.responseString);
if ([compareString isEqualToString:self.responseString])
{
NSLog(#"String Compare, Controller Found!");
[self.controllerList addObject:aStr];
//NSData *controllerIP = [aStr dataUsingEncoding:NSUTF8StringEncoding];
[[NSNotificationCenter defaultCenter] postNotificationName:#"DiscoveredController" object:nil];
return YES;
}
return NO;
}

I have the following code for SSDP search in my app:
-(void)discoverDevices {
ssdpSock = [[AsyncUdpSocket alloc] initWithDelegate:self];
[ssdpSock enableBroadcast:TRUE error:nil];
NSString *str = #"M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMan: \"ssdp:discover\"\r\nST: mydev\r\n\r\n";
[ssdpSock bindToPort:0 error:nil];
[ssdpSock joinMulticastGroup:#"239.255.255.250" error:nil];
[ssdpSock sendData:[str dataUsingEncoding:NSUTF8StringEncoding]
toHost: #"239.255.255.250" port: 1900 withTimeout:-1 tag:1];
[ssdpSock receiveWithTimeout: -1 tag:1];
[NSTimer scheduledTimerWithTimeInterval: 5 target: self
selector:#selector(completeSearch:) userInfo: self repeats: NO]; }
-(void) completeSearch: (NSTimer *)t {
NSLog(#"%s",__FUNCTION__);
[ssdpSock close];
ssdpSock = nil;}
- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port{
NSLog(#"%s %d %# %d",__FUNCTION__,tag,host,port);
NSString *aStr = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"%#",aStr);}
It uses the AsyncUdpSocket from CocoaAsyncSocket.

OK, finally done it. Found a class in the public domain (thanks Chris) called AsyncUdpSocket that lets you create a UDP socket which you can then turn on broadcasting and join the multicast address.
There is a nice sendData method, complete with adding to a run loop to prevent blocking.
Hope that helps.
Dave

Related

Application Freezing when calling CocoaAsyncMethod scheduleDequeueRead

I'm using CocoaAsyncSocket library to create a TCP socket connection. The problem I'm having is after a few library methods are called, I'm getting an error.
appDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
socket = [[AsyncSocket alloc] initWithDelegate:self];
NSError *error = nil;
if (![socket connectToHost:#"199.5.83.63" onPort:11005 error:&error])
{
NSLog(#"Error connecting: %#", error);
}
[socket readDataWithTimeout:10 tag:1];
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[tekMatrixViewController alloc] initWithNibName:#"tekMatrixViewController" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
And here are my methods from the CocoaAsyncSocket Library:
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSData *strData = [data subdataWithRange:NSMakeRange(0, [data length])];
NSString *msg = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding];
NSLog(#"RX length: %d", [data length]);
if(msg)
{
NSLog(#"RX:%#",msg);
}
else
{
NSLog(#"Fail");
}
}
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
NSLog(#"error - disconnecting");
//start reconnecting procedure here...
}
- (void)onSocketDidDisconnect:(AsyncSocket *)sock
{
NSLog(#"disconnected");
}
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
NSLog(#"connected");
}
When I run my app in the simulator, this is what my output log spits out:
2012-06-08 13:17:30.808 tekMatrix[2793:f803] connected
2012-06-08 13:17:30.815 tekMatrix[2793:f803] RX length: 8
2012-06-08 13:17:30.816 tekMatrix[2793:f803] Fail
After that, I get an error in the AsyncSocket.m file (part of library) in this method:
- (void)scheduleDequeueRead
{
if((theFlags & kDequeueReadScheduled) == 0)
{
theFlags |= kDequeueReadScheduled;
[self performSelector:#selector(maybeDequeueRead) withObject:nil afterDelay:0 inModes:theRunLoopModes];
}
}
Specifically, the error is on line:
[self performSelector:#selector(maybeDequeueRead) withObject:nil afterDelay:0 inModes:theRunLoopModes];
And the exception is: Thread 1: BAD_EXC_ACCESS (code 1=0, address=0xd0688b8a)
After that, the app is completely frozen in the simulator. If anybody could offer some insight as to why this is causing the app to freeze, I would really appreciate it.
Here is the library I'm using: CocoaAsyncSocket
EDIT:
After Enabling Zombie Objects and running the app in the simulator, this is spit out in the output:
2012-06-08 14:53:15.416 tekMatrix[3217:f803] *** -[__NSArrayI count]: message sent to deallocated instance 0x6d10a70
I'll have to do a little digging on this and figure out what's happening.
EDIT 2:
After a little digging using instruments, I found out the following:
An Objective-C message was sent to a deallocated object (zombie) at address: 0x6b8bb10.
EDIT 3:
Now the error reads:
Thread 1: EXC_BREAKPOINT(code=EXC_I386_BPT, subcode=0x0)
Here is a screenshot from instruments. I'm not really following how to interpret this, though. It looks like I'm sending a message to an object that has been deallocated. Is this true? If so, how do I go about figuring out where this occurs?
If the image is hard to see, here's a direct link: Instruments Screenshot
You are trying to access a object, that doesnt exsits anymore. Probably you are under-retaining/over-releasing it.
see this answer for a tool to find such objects: How do I set up NSZombieEnabled in Xcode 4?
I know it's way after the fact, but I just had this same exact problem. The solution was adding the ARC flag to AsyncSocket.m, -fobjc-arc
:)

AsyncSockets - ReadToData - Doesn't work like expected

It's my first specific question here on stackoverflow, cause I couldn't found any helpful solutions for my problem yet.
I need a low level socket connection between my iPhone and OSX Workstation (as TCP Server), to interchange some media data like pictures or audio files. So I think AsyncSockets is a good choise to get this to work. I've often used it for some tiny byte communication.
My Problem is, that I want to use a kind of a header/protocol to tell the server how much data bytes are still in pipe.
A simple communication like "hello world" is working fine, so there are no connection problems.
The mobile device (that wants to send a picture) does the following.
[self setHost:#"172.22.42.207"];
self.socket = [[[AsyncSocket alloc] initWithDelegate:self] autorelease];
NSError *err = nil;
[[self socket] connectToHost:self.host onPort:5009 error:&err];
...
NSData *t = UIImagePNGRepresentation(test);
NSString *header = [NSString stringWithFormat:#"%i", t.length];
NSMutableData *headerData = [[header dataUsingEncoding:NSUTF8StringEncoding] mutableCopy];
[headerData appendBytes:[AsyncSocket CRLFData] length:[[AsyncSocket CRLFData] length]];
[[self socket] writeData:headerData withTimeout:-1 tag:0];
The server is listening that way:
AsyncSocket *s = [[AsyncSocket alloc] initWithDelegate:self];
NSError *err = nil;
[s acceptOnPort:5009 error:&err];
if(err)
NSLog(#"EPIC FAIL...\n%#", err);
....
- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
{
NSLog(#"%s", __PRETTY_FUNCTION__);
[newSocket readDataToData:[AsyncSocket CRLFData] withTimeout:-1 tag:0];
}
Now: If I use readData:withTimeout:tag it all works like a charm. But once I change the code to readDataToData:withTimeout:tag, to split the header from the other content, the onSocket:didConnectToHost:port: method is never called. Here are some pretty function logs (I placed them in every delegate method)
Client side:
2012-01-31 13:40:32.962 AVMobile[20643:10703] -[SLViewController onSocket:didConnectToHost:port:]
2012-01-31 13:40:32.964 AVMobile[20643:10703] -[SLViewController onSocket:didWriteDataWithTag:]
Server side:
2012-01-31 13:40:32.961 AVServer[20618:707] -[SLAppDelegate onSocket:didAcceptNewSocket:]
So, next idea... just compare the sending and receiving bytes, so:
Sending: <33333736 35365cba>
Receiving: <33333736 35365cba>
Yeah... now my final question: What am I doing wrong!?
Why isn't it working out for me :)?
Greetings & thanks!
sniperosx
Found a solution:
Just don't use -1 as timeout.
With -1 timeout the AsyncSocket is reading data until the other side is closing the connection, so in this range no delegate method is called.
Cheerz
sniperosx
[Closed]

AsycnSocket not connecting to TCP serial port over wifi

I have an iPhone app that I run on the simulator. XCode ver 3.2.6/4.3. I am trying to communicate with a radio on a serial port of a PC over wifi, both on the same server... I've tried NSStream and GCDAsyncSocket (just to make sure). The radio has its own IP address and port number. It's actually a TCP/IP wifi module. After changing the remote access on the PC to accept my IP address, I am finally able to connect but I get kicked off immediately, I'm assuming it's when I try to read or write. Same happens when using Telnet, connects then disconnects. The radio issues HELLO when someone connects, so Telnet must try to read since data is sent. I'm guessing. I thought since I am able to connect, I should be able to read/write. (Yes, newbie here)
I would appreciate any thoughts or direction. I've been researching for over a week now and going bonkers.
Thanks. I added the code below as well as the error message.
This is the error message:
socketDidDisconnect:withError: "Error Domain=NSOSStatusErrorDomain
Code=-9844 "The operation couldn’t be completed. (OSStatus error
-9844.)" UserInfo=0x4c38a60 {}"
- (IBAction)performConnection:(id)sender
{
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
uint16_t port = [[[self serverPort] text] intValue];
if (![asyncSocket connectToHost:[serverAddr text] onPort:port error:&error])
{
DDLogError(#"Unable to connect due to invalid configuration: %#", error);
[self debugPrint:[NSString stringWithFormat:#"Unable to connect due to invalid configuration: %#", error]];
}
else
{
DDLogVerbose(#"Connecting...IP:%#, port:%i", [serverAddr text], port);
}
}
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
DDLogInfo(#"socket:%p didConnectToHost:%# port:%hu", sock, host, port);
NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithCapacity:3];
[settings setObject:#"XXX.XXX.X.XXX"
forKey:(NSString *)kCFStreamSSLPeerName];
// In fact, don't even validate the certificate chain
[settings setObject:[NSNumber numberWithBool:NO]
forKey:(NSString *)kCFStreamSSLValidatesCertificateChain];
[settings setObject:(NSString*)kCFStreamPropertySocketSecurityLevel
forKey:(NSString*)kCFStreamSocketSecurityLevelNegotiatedSSL];
DDLogVerbose(#"Starting TLS with settings:\n%#", settings);
[sock startTLS:settings];
[self debugPrint:[NSString stringWithFormat:#"socket:didConnectToHost:%# port:%hu", host, port]];
//[sock readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];
[sock readDataWithTimeout:-1 tag:0];
}
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
DDLogVerbose(#"socket:didWriteDataWithTag:");
[sock readDataWithTimeout:-1 tag:0];
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
DDLogVerbose(#"socket:didReadData:withTag:");
NSString *response = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"read response:%#", response);
[self debugPrint:[NSString stringWithFormat:#"Read: \n%#",response]];
[response release];
//NSData *newline = [#"\n" dataUsingEncoding:NSASCIIStringEncoding];
//[sock readDataToData:newline withTimeout:-1 tag: 0];
[sock readDataWithTimeout:-1 tag:0];
}
- (IBAction)sendBuf:(id)sender
{
if ([[bufOut text] length] > 0)
{
NSString *requestStr = [NSString stringWithFormat:#"%#\r\n", [bufOut text]];
NSLog(#"Sending:%#",requestStr);
NSData *requestData = [requestStr dataUsingEncoding:NSASCIIStringEncoding];
[asyncSocket writeData:requestData withTimeout:-1.0 tag:0];
[self debugPrint:[NSString stringWithFormat:#"Sent: \n%#",requestStr]];
}
}
I found a partial solution (by sheer accident). It seems the radio or how the radio is setup only allows me to connect/read/write if my app or iMac initiates the connection. It's fine with another PC. Both can initiate a connection and everything works. Still need to resolve this but at least I know my code is working.
Thanks to anyone who gave my problem some thought.

iphone :client-server communication not occuring

i had made the following programming for client server programming but it is not working. the server is not able to receive the request for connection setup.plz help.
#import "clientserverprogramViewController.h"
#import "secondview.h"
#import <CoreFoundation/CFSocket.h>
#include <sys/socket.h>
#include <netinet/in.h>
NSInputStream *iStream;
NSOutputStream *oStream;
#implementation clientserverprogramViewController
#synthesize name,filepath,display;
-(IBAction) print {
NSString *urlStr = serverIP;]
[display setText : urlStr];
if (![urlStr isEqualToString:#""]) {
NSURL *website = [NSURL URLWithString:urlStr];
if (!website) {
NSLog(#"%# is not a valid URL");
return;
}
NSHost *host = [NSHost hostWithName:[website host]];
[NSStream getStreamsToHost:host port:3000 inputStream:&iStream outputStream:&oStream];
[iStream retain];
[oStream retain];
[iStream setDelegate:self];
[oStream setDelegate:self];
[iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[oStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[iStream open];
[oStream open];
}
}
-(IBAction) settings {
[self presentModalViewController:nextview animated: YES];
}
-(IBAction) cancel {
exit(0);
}
- (void)dealloc {
[super dealloc];
}
#end
You only open streams and don't do anything with them. It's like picking up a phone and not dialing a number. Use NSStreamDelegate protocol to implement data transmission code.
Update:
You have these lines that set the delegate for streams:
[iStream setDelegate:self];
[oStream setDelegate:self];
Now implement methods that are defined in NSStreamDelegate protocol in your own class (AFAIK - there's only one of them). See how to receive/send data from there.
Is there a specific reason you're using streams?
What about using NSURLConnection? Here's a piece of code from a project of mine. Both are in KANetworkManager. KANetworkTransactionType is simply a enum that helps me know how to parse the response.
+ (void) createAndStartUrlConnection:(NSMutableURLRequest *)request type:(KANetworkTransactionType)type target:(id)target callback:(SEL)callback;
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSDictionary *requestDict = [NSDictionary dictionaryWithObjectsAndKeys:request, #"request", [NSNumber numberWithInt:type], #"type", target, #"target", [NSValue valueWithPointer:callback], #"callback", nil];
[KANetworkManager performSelectorInBackground:#selector(makeNetworkCall:) withObject:requestDict];
}
I'm able to made a synchronous network call because I always call this method on its own thread. It's a simpler way to achieve asynchronous network communications without dealing with delegates (although the delegate method provides some benefits). Your parseResponse method would need to be specific to whatever your web service it sending back. parseResponse would notify the callback method. Let me know if you have additional questions regarding this.
+ (void) makeNetworkCall:(NSDictionary *)params
{
// We assume this method won't be called from the main thread, so we need our own NSAutoreleasePool.
NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init];
NSMutableURLRequest *request = [params objectForKey:#"request"];
KANetworkTransactionType type = [(NSNumber *)[params objectForKey:#"type"] intValue];
id target = [params objectForKey:#"target"];
SEL callback = (SEL)[[params objectForKey:#"callback"] pointerValue];
NSURLResponse *response;
NSError *err;
// We make a synchronous request assuming we're on a background thread.
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
if (data.length > 0)
{
[self parseResponse:data type:type target:target callback:callback];
}
else
{
NSLog(#"Error occured during network call. %#", err);
}
[autoreleasePool drain];
}
JB gates,
In your code you inform iStream and oStream that your clientserverprogramViewController object is to be the delegate for each. However, a proper delegate needs actual implementation. Your class needs to implement this method:
– stream:handleEvent:
The details are documented here:
Reading From Input Streams
Writing To Output Streams
Also, your code will not work on a real iPhone. There is an updated Core Foundation API for creating the socket pair, details here.
Update
Just wondering if this is not a software issue but maybe the server is behind a firewall. Please give details what the server is, ie webserver, netcat, or simple TCP socket, etc.
Peter

Cocoa-Touch framework for speaking to a TCP socket? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 6 years ago.
Improve this question
I have a daemon running on a server that's latched onto a TCP/IP port. I'm looking to see if there's currently any support iPhone/Cocoa-touch frameworks that gives a nice OO wrapper for speaking to the daemon over an IP socket. I need to be able to interactively query the daemon with commands and retrieve back information.
If there isn't any OO wrappers for such a task, what's the next best bet?
http://code.google.com/p/cocoaasyncsocket/
This is what you want.
Here is some sample code from the previously mentioned AsyncSocket code that I modified into a class called SocketCommunicationManager.
A few things to note:
Our messages are being delimited with newline characters (\n) so when reading data from the socket I had to make sure to use the right constant from the AsyncSocket class (LFData in our case). AsyncSocket also provides CRLFData, CRData, and ZeroData as predefined message delimiters.
I set up the SocketCommunicationManager to always wait for an incoming message after I received and acted on a previous one. To accomplish that I used the (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag method. This method will wait until data is written to the socket, read up until the specified delimiter, and then call the delegate method (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
The SocketCommunicationManager uses NSNotificationCenter to publish any messages received from the socket. These messages are named kNotification and the message is put into the userInfo dictionary using the kNotificationMessage key.
Everything read from the socket is wrapped in an NSData object, so you'll have to decode that data after it is received.
Here's the code:
#import <Foundation/Foundation.h>
extern NSString * const kNotification;
extern NSString * const kNotificationMessage;
#class AsyncSocket;
#interface SocketCommunicationManager : NSObject {
AsyncSocket *socket;
BOOL isRunning;
NSNotificationCenter* notificationCenter;
}
#property (readwrite, assign) BOOL isRunning;
- (void)connectToHost:(NSString *)hostName onPort:(int)port;
- (void)sendMessage:(NSString *)message;
- (void)disconnect;
#end
#import "SocketCommunicationManager.h"
#import "AsyncSocket.h"
NSString * const kNotification = #"kNotification";
NSString * const kNotificationMessage = #"kNotificationMessage";
#implementation SocketCommunicationManager
#synthesize isRunning;
- (id) init {
if (!(self = [super init]))
return nil;
socket = [[AsyncSocket alloc] initWithDelegate:self];
[self setIsRunning:NO];
notificationCenter = [NSNotificationCenter defaultCenter];
return self;
}
- (void)connectToHost:(NSString *)hostName onPort:(int)port {
if (![self isRunning]) {
if (port < 0 || port > 65535)
port = 0;
NSError *error = nil;
if (![socket connectToHost:hostName onPort:port error:&error]) {
NSLog(#"Error connecting to server: %#", error);
return;
}
[self setIsRunning:YES];
} else {
[socket disconnect];
[self setIsRunning:false];
}
}
- (void)disconnect {
[socket disconnect];
}
- (void)dealloc {
[super dealloc];
[socket disconnect];
[socket dealloc];
}
- (void)sendMessage:(NSString *)message {
NSString *terminatedMessage = [message stringByAppendingString:#"\r\n"];
NSData *terminatedMessageData = [terminatedMessage dataUsingEncoding:NSASCIIStringEncoding];
[socket writeData:terminatedMessageData withTimeout:-1 tag:0];
}
#pragma mark AsyncSocket Delegate
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port {
NSLog(#"Connected to server %#:%hu", host, port);
[sock readDataToData:[AsyncSocket LFData] withTimeout:-1 tag:0];
}
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSData *truncatedData = [data subdataWithRange:NSMakeRange(0, [data length] - 1)];
NSString *message = [[[NSString alloc] initWithData:truncatedData encoding:NSASCIIStringEncoding] autorelease];
if (message)
NSLog(#"%#", message);
else
NSLog(#"Error converting received data into UTF-8 String");
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:message forKey:kNotificationMessage];
[notificationCenter postNotificationName:kNotification object:self userInfo:userInfo];
[sock readDataToData:[AsyncSocket LFData] withTimeout:-1 tag:0];
}
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag {
[sock readDataToData:[AsyncSocket LFData] withTimeout:-1 tag:0];
}
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err {
NSLog(#"Client Disconnected: %#:%hu", [sock connectedHost], [sock connectedPort]);
}
#end
Roughly speaking, going up the stack you have:
BSD sockets
CFSocket
CFReadStream/CFWriteStream/NSInputStream/NSOutputStream
CFHTTPStream
NSURLConnection
Sounds like you want CFSocket, or possibly CFStream.
Did you check out the BSD Sockets in Cocoa-Touch's networking guide?
As Genericrich points out, the Cocoa Async Socket framework is the way to go. This has been around for a while and seen a good deal of use. http://code.google.com/p/cocoaasyncsocket/
As pointed out by Genericrich, the AsyncSocket class is just wonderful for dealing with sockets.
http://code.google.com/p/cocoaasyncsocket/