昨天在os x上写了个网络通信的小程序http://blog.csdn.net/zj510/article/details/8934312,今天在iphone也试了一下。
使用了Cocoa中的NSStream.代码相当的简单。
- (void)Work_Thread:(NSURL *)url { NSString* strHost = [url host]; int port = [[url port] integerValue]; [NSStream getStreamsToHostNamed:strHost port: port inputStream:&readStream outputStream:&writeStream]; [readStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType]; [readStream setDelegate:self]; [readStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [readStream open]; NSLog(@"VOIP stream, %x", readStream); [writeStream open]; [writeStream write:"abcd" maxLength:4]; NSInputStream* iStream; [NSStream getStreamsToHostNamed:strHost port:port inputStream:&iStream outputStream:nil]; [iStream setDelegate: self]; [iStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [iStream open]; NSLog(@"normal stream: %x", iStream); [[NSRunLoop currentRunLoop] run]; }这是个线程函数,里面创建了2个socket连接,并且关联到当前线程的run-loop。
为了接收NSStream的事件,需要实现NSStreamDelegate,如
@interface KMasterViewController : UITableViewController <NSStreamDelegate>
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode { NSLog(@" >> NSStreamDelegate in Thread %@", [NSThread currentThread]); switch (eventCode) { case NSStreamEventHasBytesAvailable: { uint8_t buf[100] = {0}; int numBytesRead = [(NSInputStream *)stream read:buf maxLength:100]; NSString* str = [NSString stringWithFormat:@"recv: %s", buf]; UILocalNotification* n = [[[UILocalNotification alloc] init] autorelease]; [n setAlertBody:[NSString stringWithFormat:@"notify: %x", stream]]; [[UIApplication sharedApplication] presentLocalNotificationNow:n]; break; } case NSStreamEventErrorOccurred: { break; } case NSStreamEventEndEncountered: { break; } default: break; } }收到数据后,显示一条notification。
就这么简单,使用http://blog.csdn.net/zj510/article/details/8934312里面的server,打开iphone程序,就可以收数据了。
但是这里有一个问题,iphone程序切到后台后,socket连接会断掉,ios的设计就是这样,好在apple公司也没有那么绝,还是有一些东西可以在后台运行的,比如:
1. 音乐
2. gps
3. voip
这里我们可以将NSStream指定voip的属性,从而可以避免程序切到后台的时候socket连接中断。
步骤如下:
1. 在info.plist文件中,增加voip选项,如
2. 设置NSStream的属性,如
[readStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType];
这样的话,当这个程序切到后台后,只有voip属性的那个socket还有效,另外一个将会失效。我测试了一下,确实是这样的。
另外,iphone都是通过wifi或者gprs上网的,那么当socket连接空闲一段时间后,这个连接有可能被路由器关闭,为了保持连接,我们需要不停发送心跳包。
由于iphone上的程序切到后台后,程序会被挂起,那么也就无法定时发送心跳包,所以这个问题只能由服务端来解决。普通的办法就是服务器每隔一定时间给每个客户端发送一个心跳包,以维持这个连接。每当客户端接收到心跳包的时候,客户端会被IOS唤醒,获得一小段CPU时间,然后再次进入挂起状态。
相关测试代码:http://download.csdn.net/detail/zj510/5390813