public
Last active

How to open a TCP socket in Objective-C

  • Download Gist
Communicator.h
Objective-C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#import <Foundation/Foundation.h>
 
@interface Communicator : NSObject <NSStreamDelegate> {
@public
NSString *host;
int port;
}
 
- (void)setup;
- (void)open;
- (void)close;
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)event;
- (void)readIn:(NSString *)s;
- (void)writeOut:(NSString *)s;
 
@end
Communicator.m
Objective-C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
#import "Communicator.h"
 
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
 
NSInputStream *inputStream;
NSOutputStream *outputStream;
 
@implementation Communicator
 
- (void)setup {
NSURL *url = [NSURL URLWithString:host];
NSLog(@"Setting up connection to %@ : %i", [url absoluteString], port);
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (CFStringRef)[url host], port, &readStream, &writeStream);
if(!CFWriteStreamOpen(writeStream)) {
NSLog(@"Error, writeStream not open");
return;
}
[self open];
NSLog(@"Status of outputStream: %i", [outputStream streamStatus]);
return;
}
 
- (void)open {
NSLog(@"Opening streams.");
inputStream = (NSInputStream *)readStream;
outputStream = (NSOutputStream *)writeStream;
[inputStream retain];
[outputStream retain];
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
}
 
- (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 release];
[outputStream release];
inputStream = nil;
outputStream = nil;
}
 
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)event {
NSLog(@"Stream triggered.");
switch(event) {
case NSStreamEventHasSpaceAvailable: {
if(stream == outputStream) {
NSLog(@"outputStream is ready.");
}
break;
}
case NSStreamEventHasBytesAvailable: {
if(stream == inputStream) {
NSLog(@"inputStream is ready.");
uint8_t buf[1024];
unsigned int len = 0;
len = [inputStream read:buf maxLength:1024];
if(len > 0) {
NSMutableData* data=[[NSMutableData alloc] initWithLength:0];
[data appendBytes: (const void *)buf length:len];
NSString *s = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
[self readIn:s];
[data release];
}
}
break;
}
default: {
NSLog(@"Stream is sending an Event: %i", event);
break;
}
}
}
 
- (void)readIn:(NSString *)s {
NSLog(@"Reading in the following:");
NSLog(@"%@", s);
}
 
- (void)writeOut:(NSString *)s {
uint8_t *buf = (uint8_t *)[s UTF8String];
[outputStream write:buf maxLength:strlen((char *)buf)];
NSLog(@"Writing out the following:");
NSLog(@"%@", s);
}
 
@end
StreamExample.m
Objective-C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#import <Foundation/Foundation.h>
 
#import "Communicator.h"
 
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
Communicator *c = [[Communicator alloc] init];
c->host = @"http://127.0.0.1";
c->port = 6789;
[c setup];
[c open];
[pool drain];
return 0;
}

How do i receive data?

I have quite the same implementation as yours on my iOS app, but the messages written in the output stream are sent to my server only when the app is killed (stopped by xcode or killed in the iOS dock).
Are your messages sent right after the write:maxLength: call ?

Edit: Problem solved, apparently the message must finish with a "\n" to flush the output stream !

@traff589: sometimes I believe it requires "\r\n", that is just to be extra safe in case newline by itself is not working.

Anyhow, if your project uses ARC, just remove references to [retain] and [release], along with NSAutoReleasePool

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.