Use Case
I'm using sockets to send and receive data using CFStreamCreatePairWithSocketToHost() and am trying to wrap my head around how this is done when send multiple sets of data (i.e. not just 1 request).
Problem
Currently I can send data and receive a response (i.e. 1 round trip). However, after I send all the data in the outputStream the stream gets closed (i.e. receives NSStreamEventEndEncountered).
Question
So the question is, what happens when I want to send multiple data requests?
- Do I setup a new socket every time I have a new data object to send?
- Do I have to reset
outputStreamand send more data.
Code
Most of this code came from the Cocoa Streams Documentation:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_data = [[NSMutableData alloc] init];
[self initNetworkCommunication];
[self sendString:@"Hello World!"];
}
- (void)initNetworkCommunication {
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"123.456.0.0", 1234, &readStream, &writeStream);
inputStream = (NSInputStream *)readStream; // ivar
[inputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
outputStream = (NSOutputStream *)writeStream; // ivar
[outputStream setDelegate:self];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream open];
}
- (void)sendString:(NSString *)string {
NSData *data = [[NSData alloc] initWithData:[string dataUsingEncoding:NSASCIIStringEncoding]];
[_data appendData:data];
[data release];
}
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
NSLog(@"stream event %u", streamEvent);
switch (streamEvent) {
case NSStreamEventOpenCompleted:
NSLog(@"Stream opened");
break;
case NSStreamEventHasSpaceAvailable: {
uint8_t *readBytes = (uint8_t *)[_data mutableBytes];
readBytes += byteIndex; // ivar
int data_len = [_data length];
unsigned int len = ((data_len - byteIndex >= 1024) ? 1024 : (data_len - byteIndex));
uint8_t buf[len];
(void)memcpy(buf, readBytes, len);
len = [(NSOutputStream *)theStream write:(const uint8_t *)buf maxLength:len];
NSLog(@"Sending buffer of len: %d", len);
byteIndex += len;
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 sendString:@"Another Test"];
}
break;
case NSStreamEventErrorOccurred:
NSLog(@"Can not connect to the host!");
break;
case NSStreamEventEndEncountered:
NSLog(@"Closing stream...");
[theStream close];
[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[theStream release];
theStream = nil;
break;
default:
NSLog(@"Unknown event");
}
}
Response:
2012-08-15 08:16:30.896 Sockets[34836:f803] Opened input stream.
2012-08-15 08:16:30.898 Sockets[34836:f803] Opened output stream.
2012-08-15 08:16:30.899 Sockets[34836:f803] Sending buffer of len: 12
2012-08-15 08:16:30.900 Sockets[34836:f803] Sending buffer of len: 0
2012-08-15 08:16:30.901 Sockets[34836:f803] Closing output stream.
2012-08-15 08:16:30.939 Sockets[34836:f803] server said: Hello World!
Note the outputStream stream closes after I send the data. I try reinitiating outputStream before [self sendString:@"Another Test"];. I also tried idz's answer.
Per the documentation, I believe the Sending buffer of len: 0 is my problem.
If the delegate receives an NSStreamEventHasSpaceAvailable event and does not write anything to the stream, it does not receive further space-available events from the run loop until the NSOutputStream object receives more bytes. When this happens, the run loop is restarted for space-available events.
However, the documentation doesn't say anything about closing the stream when the end of the stream is reached. So I'm confused…