原文链接:http://blog.csdn.net/zj510/article/details/8935683
昨天在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];
- }
为了接收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;
- }
- }
就这么简单,使用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];
这样,当程序切到后台的时候,这个socket连接还会被保持。上面的示例代码里面有2个连接,一个采用了voip属性,另外一个没有。
这样的话,当这个程序切到后台后,只有voip属性的那个socket还有效,另外一个将会失效。我测试了一下,确实是这样的。
另外,iphone都是通过wifi或者gprs上网的,那么当socket连接空闲一段时间后,这个连接有可能被路由器关闭,为了保持连接,我们需要不停发送心跳包。
由于iphone上的程序切到后台后,程序会被挂起,那么也就无法定时发送心跳包,所以这个问题只能由服务端来解决。普通的办法就是服务器每隔一定时间给每个客户端发送一个心跳包,以维持这个连接。每当客户端接收到心跳包的时候,客户端会被IOS唤醒,获得一小段CPU时间,然后再次进入挂起状态。
相关测试代码:http://download.csdn.net/detail/zj510/5390813