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