I have implemented socket connection in iOS.
What I want to do is to send string of data to the connected device...
(I am able to receive data when someone sends to my device)
I have tried this code but data is getting received on other device, when I close my app.
- (IBAction)connectToServer:(id)sender {
NSLog(#"Setting up connection to %# : %i", _ipAddressText.text, [_portText.text intValue]);
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef) _ipAddressText.text, [_portText.text intValue], &readStream, &writeStream);
messages = [[NSMutableArray alloc] init];
[self open];
}
- (void)open {
NSLog(#"Opening streams.");
outputStream = (__bridge NSOutputStream *)writeStream;
inputStream = (__bridge NSInputStream *)readStream;
[outputStream setDelegate:self];
[inputStream setDelegate:self];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream open];
[inputStream open];
_connectedLabel.text = #"Connected";
}
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
NSLog(#"stream event %lu", streamEvent);
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
_connectedLabel.text = #"Connected";
break;
case NSStreamEventHasBytesAvailable:
if (theStream == inputStream)
{
uint8_t buffer[1024];
NSInteger len;
while ([inputStream hasBytesAvailable])
{
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0)
{
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
if (nil != output)
{
NSLog(#"server said: %#", output);
[self messageReceived:output];
}
}
}
}
break;
case NSStreamEventHasSpaceAvailable:
NSLog(#"Stream has space available now");
break;
case NSStreamEventErrorOccurred:
NSLog(#"error: %#",[theStream streamError].localizedDescription);
break;
case NSStreamEventEndEncountered:
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
_connectedLabel.text = #"Disconnected";
NSLog(#"close stream");
break;
default:
NSLog(#"Unknown event");
}
}
/* Sends data to other device */
- (IBAction) sendMessage {
NSLog(#"sendMessage");
NSString *response = [NSString stringWithFormat:#"msg:%#", _dataToSendText.text];
NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
NSLog(#"[data length] %lu",(unsigned long)[data length]);
[outputStream write:[data bytes] maxLength:[data length]];
}
Where I am making mistake?
After doing hard research i found adding \n at the end of string message indicates my buffer has received whole string.
now start sending a file, so it worked...
To send a String over Sockets, you must mark the end of the string. ie; Add a \n
To mark a string with start and end of string there are ASCII control characters to do so, the octets are \002 & \003 respectively. I would recommend using these control characters instead of just adding a line break, your text could have line breaks and that could create problems.
Related
I have two Applaction one is the client (IOS device) and the other one is the server (PC device).
I would like to get the ip address in the client (IOS device ) Automatically.
I'm using this line of code to type the IP address
NSString *ipAddressText = #"192.168.211.62";
I don't want to keep typing the Ip address, becuase the IP address will change most of the time.
here's my code
-(void)viewDidLoad{
[super viewDidLoad];
NSString *ipAddressText = #"192.148.211.42";
NSLog(#"Setting up connection to %# : %i", ipAddressText, 111);
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef) ipAddressText, 111, &readStream, &writeStream);
messages = [[NSMutableArray alloc] init];
[self open];
}
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
NSLog(#"stream event %lu \n ", streamEvent);
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
_connectedLabel.text = #"Connected";
break;
case NSStreamEventHasBytesAvailable:
if (theStream == inputStream)
{
uint8_t buffer[1024];
NSInteger len;
while ([inputStream hasBytesAvailable])
{
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0)
{
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
if (nil != output)
{
NSLog(#"server said: %# \n ", output);
[self messageReceived:output];
}
}
}
}
break;
case NSStreamEventHasSpaceAvailable:
NSLog(#"Stream has space available now");
break;
case NSStreamEventErrorOccurred:
NSLog(#"%#\n",[theStream streamError].localizedDescription);
break;
case NSStreamEventEndEncountered:
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
_connectedLabel.text = #"Disconnected";
NSLog(#"close stream");
break;
default:
NSLog(#"Unknown event");
}
}
- (void)open {
NSLog(#"Opening streams.");
outputStream = (__bridge NSOutputStream *)writeStream;
inputStream = (__bridge NSInputStream *)readStream;
[outputStream setDelegate:self];
[inputStream setDelegate:self];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream open];
[inputStream open];
_connectedLabel.text = #"Connected";
}
- (void)close {
NSLog(#"Closing streams.");
[inputStream close];
[outputStream close];
[inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream setDelegate:nil];
[outputStream setDelegate:nil];
inputStream = nil;
outputStream = nil;
_connectedLabel.text = #"Disconnected";
}
This is in Swift, but can easily be dropped into any Xcode project.
NB: This example is taken from a GitHub project Host.swift.
Getting information about network interfaces in Unix type systems like iOS or Mac OS X requires using some arcane C APIs. These APIs have varying amounts of visibility in swift and objective-c, ios and mac-os-x.
If you're exclusively targeting macOS with Objective-C, then nshost is your best solution. However, if you require iOS compatibility then you'll have to drop down to lower level C API such as getifaddrs(...) or cfhost.
If you want a swift based solution even getifaddrs(...) comes with some bridging header requirements (making it unusable in a Framework).
Here is an example using CFHost and sockaddr_in struct that will work in Swift and on macOS and iOS (even in Frameworks). See Host.swift on GitHib for a fully working example.
Use CFHost to get the addressing info, this will be a CFArray of CFData objets.
let sockaddrs = CFHostGetAddressing("apple.com", &resolved)?.takeRetainedValue()
Get the first object
let data = CFArrayGetValueAtIndex(sockaddrs, 0)
Cast the bytes into a sockaddr struct
var storage = sockaddr_storage()
data.getBytes(&storage, length: sizeof(sockaddr_storage))
Then force the sockaddr struct into a sockaddr_in struct so we can use it
let addr = withUnsafePointer(&storage) { UnsafePointer<sockaddr_in>($0).memory
Use the inet_ntoa(...) function to turn addr.sin_addr (IP address) into a C-string. We can then use String(Cstring: encoding:) to get a nice String of the IP Address.
let address = String(CString: inet_ntoa(addr.sin_addr), encoding: NSUTF8StringEncoding)
Here is a GitHub project called Host.swift that I created to solve these issues using the technique above.
I have this sample code taken from the example of this iPhone chat server.
In my case I need to send larger amounts of data, 100k-200k thus I changed the buffer size to something that can accommodate what I want.
On the iOS simulator (emulating a 6plus) everything works perfectly, as soon as I try to debug on my iPhone 6plus after implementing the suggestions of #tc. I get the incoming message broken into 3-4 parts! Any ideas?
2015-02-03 22:42:34.756 Sock1[7390:3773054] Incoming message: XML part 1
2015-02-03 22:42:34.759 Sock1[7390:3773054] Incoming message: XML part 2
2015-02-03 22:42:34.774 Sock1[7390:3773054] Incoming message: XML part 3
2015-02-03 22:42:34.794 Sock1[7390:3773054] Incoming message: XML part 4
XML part 1-4 make up the entire message that should have been in one as there is no null byte character within.
Just to make things even stranger, when I add a break point on this line:
[currentMessage appendBytes:buffer length:len];
and go through step by step (69-70 pressing Continue) everything works fine! No errors at all! So it is something to do with the speed of parsing or receiving or something I can't figure out?
What I've made sure is that the server doesn't send any null byte characters apart from the terminating one at the end of the message.
The code I use is this:
#implementation ViewController
bool connectionError = true;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)initNetworkCommunication {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (CFStringRef)#"192.168.1.1", 6035, &readStream, &writeStream);
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (__bridge NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
}
- (void)closeAll {
NSLog(#"Closing streams.");
[inputStream close];
[outputStream close];
[inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream setDelegate:nil];
[outputStream setDelegate:nil];
inputStream = nil;
outputStream = nil;
}
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
connectionError = false;
if (theStream == inputStream) {
uint8_t buffer[1024];
long len;
NSMutableData *currentMessage;
currentMessage = [NSMutableData dataWithBytes:"" length:strlen("")];
while ([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
[currentMessage appendBytes:buffer length:len];
}
NSString *newMessage = [[NSString alloc] initWithData:currentMessage encoding:NSUTF8StringEncoding];
NSLog(#"Incoming message: %#",newMessage);
NSData *nullByte = [NSMutableData dataWithLength:1];
len = currentMessage.length;
NSRange searchRange = {0, len};
for (NSRange r; (r = [currentMessage rangeOfData:nullByte options:0 range:searchRange]).length; ) {
NSString *message = [[NSString alloc] initWithBytes:currentMessage.bytes length:r.location encoding:NSUTF8StringEncoding];
searchRange.location = r.location+r.length;
searchRange.length = len - searchRange.location;
[self messageReceived:message];
}
[currentMessage replaceBytesInRange:(NSRange){0, searchRange.location} withBytes:NULL length:0];
}
break;
case NSStreamEventErrorOccurred:
NSLog(#"Can not connect to the host!");
connectionError = true;
[self closeAll];
[self connectionLost];
break;
case NSStreamEventEndEncountered:
break;
default:
NSLog(#"Unknown event");
}
}
- (void) connectionLost {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Alert!"
message:#"Connection to the server lost!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
- (void) messageReceived:(NSString *)message {
[messages addObject:message];
if (inputStream.streamStatus == NSStreamStatusClosed || inputStream.streamStatus == NSStreamStatusError || inputStream.streamStatus == NSStreamStatusNotOpen) {
[self closeAll];
[self initNetworkCommunication];
}
// do things with the message, XML parsing...
}
- (void) initConnection {
[self initNetworkCommunication];
messages = [[NSMutableArray alloc] init];
}
- (IBAction)joinChat:(id)sender {
[self initConnection];
[self sendSocketMessage: #"iam:" message: _inputNameField.text];
}
- (void) sendSocketMessage:(NSString*) sendCommand message:(NSString*) sendMessage
{
// do something...
if (outputStream.streamStatus == NSStreamStatusClosed || outputStream.streamStatus == NSStreamStatusError || outputStream.streamStatus == NSStreamStatusNotOpen) {
[self closeAll];
[self initNetworkCommunication];
}
NSString *response = [NSString stringWithFormat: #"%#%#", sendCommand, sendMessage];
NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
[outputStream write:[data bytes] maxLength:[data length]];
NSLog(#"clint sent: %#", response);
}
#end
The short answer is that TCP offers a stream of bytes, not a stream of variable-length messages¹. I don't know why it works in the simulator, unless 192.168.1.1 is the same machine (in which case it isn't subject to the usual flow control, though it's perhaps surprising that the kernel buffers are that big).
To work around this, you need to somehow signal where the end of a message is. There are two common ways:
Length-prefixes. Examples include DJB's netstrings (e.g. 5:abcde for the bytestring "abcde"), HTTP's Content-Length, HTTP 1.1's chunked encoding, and various binary protocols typically with 8-bit, 16-bit, or variable-length-encoded lengths.
Delimiters. Examples include newlines (traditionally CRLF, e.g. in Telnet/SMTP/HTTP/IRC), null bytes, MIME boundaries (ick).
In this case, we can make use of the fact that null bytes aren't permitted within XML. currentMessage is assumed to be a NSMutableData ivar and not nil.
while ([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
[currentMessage appendBytes:buffer length:len];
}
NSData * nullByte = [NSMutableData dataWithLength:1];
len = currentMessage.length;
NSRange searchRange = {0, len};
for (NSRange r; (r = [currentMessage rangeOfData:nullByte options:0 range:searchRange]).length; ) {
NSString * message = [[NSString alloc] initWithBytes:currentMessage.bytes length:r.location encoding:NSUTF8StringEncoding];
searchRange.location = r.location+r.length;
searchRange.length = len - searchRange.location;
[self messageReceived:message];
}
[currentMessage replaceBytesInRange:(NSRange){0, searchRange.location} withBytes:NULL length:0];
Also note that initializing things in -viewDidLoad requires some care if the view can be unloaded (this is less of an issue if you only support iOS 6+, since views are no longer automatically unloaded).
I am able to connect my iOS program to a java based socket listener and get it connected well. iOS app is also able to send screen shot image data to the socket very well. This is done under NSStreamEventHasSpaceAvailable
My problem is, i do not know, how to send this screenshot image periodically to the socket. I am sending it just once now, its working. But, i want to keep sending this image data to socket one after another screenshot taken programmatically in every certain interval. How to do that? Please advise.
Please refer my complete code below.
-(void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
{
NSString *io;
if (theStream == inputStream) io = #">>";
else io = #"<<";
NSString *event;
switch (streamEvent)
{
case NSStreamEventNone:
event = #"NSStreamEventNone";
//statusText.text = #"Can not connect to the host!";
NSLog(#"NSStreamEventNone - Can not connect to the host");
break;
case NSStreamEventOpenCompleted:
event = #"NSStreamEventOpenCompleted";
//pingButton.hidden = NO;
//statusText.text = #"Connected";
NSLog(#"Connected");
break;
case NSStreamEventHasBytesAvailable:
event = #"NSStreamEventHasBytesAvailable";
NSLog(#"NSStreamEventHasBytesAvailable called");
if (theStream == inputStream)
{
//read data
uint8_t buffer[1024];
int len;
while ([inputStream hasBytesAvailable])
{
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0)
{
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
NSData *theData = [[NSData alloc] initWithBytes:buffer length:len];
if (nil != output)
{
//do something with data
NSLog(#"NSStreamEventHasBytesAvailable theData: %#", theData);
}
}
}
}
break;
case NSStreamEventHasSpaceAvailable:
event = #"NSStreamEventHasSpaceAvailable";
NSLog(#"NSStreamEventHasSpaceAvailable called");
NSLog(#"space : %d",[outputStream hasSpaceAvailable]);
if (theStream == outputStream)
{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
UIGraphicsBeginImageContext(appDelegate.window.bounds.size);
[appDelegate.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
[data writeToFile:#"screenshot.png" atomically:YES];
int num = [outputStream write:[data bytes] maxLength:[data length]];
if (-1 == num) {
NSLog(#"Error writing to stream %#: %#", outputStream, [outputStream streamError]);
}else{
NSLog(#"Wrote %i bytes to stream %#.", num, outputStream);
//[outputStream close];
}
}
break;
case NSStreamEventErrorOccurred:
event = #"NSStreamEventErrorOccurred";
//statusText.text = #"Can not connect to the host!";
//pingButton.hidden = YES;
NSLog(#"NSStreamEventErrorOccurred - Can not connect to the host");
break;
case NSStreamEventEndEncountered:
event = #"NSStreamEventEndEncountered";
//statusText.text = #"Connection closed by the server.";
//pingButton.hidden = YES;
NSLog(#"NSStreamEventEndEncountered - Connection closed by the server");
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
//[theStream release];
theStream = nil;
break;
default:
event = #"** Unknown";
}
NSLog(#"%# : %#", io, event);
}
Under a Button click, the below code is for connecting the host initially.
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)#"localhost", 8080, &readStream, &writeStream);
inputStream = (__bridge_transfer NSInputStream *)readStream;
outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
I want to send requests to a server in my network. The first thing I did was to get my IP address. ex. 196.168.16.* . Now that I have my IP address I'll have to send request to all IP in the network with those with listening ports,ex. port 49160. So what i did was to send requests from 192.168.16.1 to 192.168.16.255 and if an IP has a listening port of 49160 they will receive my request. Then a prompt will appear to the PC ... by the way my server is a PC .. then the PC user will accept it,then i will receive a return message from them. I am able to send request in a static manner.but when i try to loop the method im using it doenst work.
Here are sample codes:
static IOStreamHelper *_sharedInstance = nil;
+ (IOStreamHelper*)sharedInstance
{
if (_sharedInstance == nil) {
_sharedInstance = [[IOStreamHelper alloc] init];
}
return _sharedInstance;
}
-(void)initWithIpAddress:(CFStringRef)ipAddr port:(int)port
{
NSString*str = (__bridge_transfer NSString*)ipAddr;
NSLog(#"initWithIP:%#:%i",str,port);
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)ipAddr, port, &readStream, &writeStream);
inputStream = (__bridge_transfer NSInputStream *)readStream;
outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
}
-(void)sendStringRequest
{
NSString*space = [NSString stringWithFormat:#"%#",[NSByteCountFormatter stringFromByteCount:[self getFreeDiskspace] countStyle:NSByteCountFormatterCountStyleFile]];
NSString *message = [NSString stringWithFormat:#"fishtune_c;%#(%#),1092809312741,jyce09#gmail.com,%#;",[self platformString],[[GetIpAndMacAddress sharedInstance] getMacAddress],space];
messageData = [[NSData alloc] initWithData:[message dataUsingEncoding:NSUTF8StringEncoding]];
[outputStream write:[messageData bytes] maxLength:[messageData length]];
}
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent
{
NSLog(#"stream event %i", streamEvent);
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
if (theStream == inputStream) {
uint8_t buffer[1024];//1024
int len;
while ([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0) {
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSUTF8StringEncoding];
if (nil != output) {
NSLog(#"server reply: %#", output);
}
}
}
}
break;
case NSStreamEventHasSpaceAvailable:
NSLog(#"Stream has space available now");
[self sendStringRequest];
break;
case NSStreamEventErrorOccurred:
{
NSLog(#"Can not connect to the host!");
NSError *theError = [theStream streamError];
NSLog(#"%#",[NSString stringWithFormat:#"%#",[theError localizedDescription]]);
}
break;
case NSStreamEventEndEncountered:
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
theStream = nil;
break;
default:
NSLog(#"Unknown event");
}
}
Then i call this method .This is the method that i want to iterate from 1 to 255:
CFStringRef aCFString = (__bridge CFStringRef)#"IPfrom 1 to 255";
[[IOStreamHelper sharedInstance] initWithIpAddress:aCFString port:49160];
I want to know how to iterate this properly. Thanks
I am using a device called a WiFly that has ip address:169.254.1.1 and port 2000. I am trying to connect to this device via an iOS application. I use the following code to connect:
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
UInt32 port = 2000;
CFStringRef host = CFSTR("169.254.1.1");
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, &readStream, &writeStream);
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (__bridge NSOutputStream *)writeStream;
// set the delegates to this view controller
[inputStream setDelegate:self];
[outputStream setDelegate:self];
// Set run loops to continuous receive information
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
// Finally, open the connection
[inputStream open];
[outputStream open];
Then I use the following to handle stream events:
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
NSLog(#"stream event %i", streamEvent);
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(#"Stream opened");
break;
case NSStreamEventHasBytesAvailable:
if (theStream == inputStream) {
uint8_t buffer[1024];
int len;
while ([inputStream hasBytesAvailable]) {
len = [inputStream read:buffer maxLength:sizeof(buffer)];
if (len > 0) {
NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSASCIIStringEncoding];
if (nil != output) {
NSLog(#"server said: %#", output);
[self messageReceived:output];
}
}
}
}
break;
case NSStreamEventErrorOccurred:
NSLog(#"Can't connect to server");
break;
case NSStreamEventEndEncountered:
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
break;
default:
NSLog(#"Unknown event");
}
So, I can see that the first two streams are opened correctly. Then it follows immediately with a stream event 4, which from my understanding is to be expected. However, I then try to call a function:
- (IBAction)moveForward
{
NSLog(#"move forward called");
NSString *response = [NSString stringWithFormat:#"2"];
NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSASCIIStringEncoding]];
[outputStream write:[data bytes] maxLength:[data length]];
}
Which should return "forward" from an arduino uno via the wifly. However, when I click, I get another NSStreamEvent 4 for some reason. I also telnetted in to the device via the terminal with:
telnet 169.254.1.1 2000
and subsequently type a "2"... This returned the desired "forward" immediately. What am I doing wrong from the perspective of the iPad?
Help is much appreciated!
EDIT For some reason, everytime the handler is accessed, the stream that is passed is the output stream, which is completely wrong... Why wouldn't the input stream ever be passed through?
And here is the arduino code:
void loop()
{ while (Serial.available() > 0) {
int next = Serial.parseInt();if(Serial.available() > 0)
{
if(next == 20) {
Serial.println("leftMove");
}}}}