title: iOS: Socket Networking Fundamentals using CFStreamCreatePairWithSocketToHost
body: <h3>Use Case</h3>
  
  <p>I'm using sockets to send and receive data using <code>CFStreamCreatePairWithSocketToHost()</code> and am trying to wrap my head around how this is done when send multiple <em>sets</em> of data (i.e. not just 1 <em>request</em>).</p>
  
  <h3>Problem</h3>
  
  <p>Currently I can send data and receive a response (i.e. 1 round trip). However, after I send all the data in the <code>outputStream</code> the stream gets closed (i.e. receives <code>NSStreamEventEndEncountered</code>).</p>
  
  <h3>Question</h3>
  
  <p>So the question is, what happens when I want to send multiple data requests?</p>
  
  <ul>
  <li>Do I setup a new socket every time I have a new data object to send?</li>
  <li>Do I have to <em>reset</em> <code>outputStream</code> and send more data.</li>
  </ul>
  
  <h3>Code</h3>
  
  <p>Most of this code came from the <a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Streams/Streams.html" rel="nofollow noreferrer">Cocoa Streams Documentation</a>:</p>
  
  <pre><code>- (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, &amp;readStream, &amp;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 &gt;= 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 &gt; 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");
      }
  }
  </code></pre>
  
  <h3>Response:</h3>
  
  <pre><code>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!
  </code></pre>
  
  <p>Note the <code>outputStream</code> stream <em>closes</em> after I send the data. I try reinitiating <code>outputStream</code> before <code>[self sendString:@"Another Test"];</code>. I also tried <strong>idz</strong>'s answer.</p>
  
  <p>Per the documentation, I believe the <em>Sending buffer of len: 0</em> is my problem.</p>
  
  <blockquote>
    <p>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.</p>
  </blockquote>
  
  <p>However, the documentation doesn't say anything about closing the stream when the end of the stream is reached. So I'm confused…</p>