现在的位置: 首页 > 综合 > 正文

IOS 网络编程 + 后台保持连接

2018年05月17日 ⁄ 综合 ⁄ 共 3211字 ⁄ 字号 评论关闭

原文链接:http://blog.csdn.net/zj510/article/details/8935683

昨天在os x上写了个网络通信的小程序http://blog.csdn.net/zj510/article/details/8934312,今天在iphone也试了一下。

使用了Cocoa中的NSStream.代码相当的简单。

  1. - (void)Work_Thread:(NSURL *)url  
  2. {  
  3.     NSString* strHost = [url host];  
  4.     int port = [[url port] integerValue];  
  5.       
  6.     [NSStream getStreamsToHostNamed:strHost port: port inputStream:&readStream outputStream:&writeStream];  
  7.       
  8.     [readStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType];  
  9.     [readStream setDelegate:self];  
  10.     [readStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];  
  11.     [readStream open];  
  12.     NSLog(@"VOIP stream, %x", readStream);  
  13.       
  14.     [writeStream open];  
  15.     [writeStream write:"abcd" maxLength:4];  
  16.       
  17.   
  18.     NSInputStream* iStream;  
  19.     [NSStream getStreamsToHostNamed:strHost port:port inputStream:&iStream outputStream:nil];  
  20.     [iStream setDelegate: self];  
  21.     [iStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];  
  22.     [iStream open];  
  23.     NSLog(@"normal stream: %x", iStream);  
  24.   
  25.     [[NSRunLoop currentRunLoop] run];  
  26.   
  27. }  

这是个线程函数,里面创建了2个socket连接,并且关联到当前线程的run-loop。

为了接收NSStream的事件,需要实现NSStreamDelegate,如

  1. @interface KMasterViewController : UITableViewController <NSStreamDelegate>  


  1. - (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode  
  2. {  
  3.     NSLog(@" >> NSStreamDelegate in Thread %@", [NSThread currentThread]);  
  4.       
  5.     switch (eventCode) {  
  6.         case NSStreamEventHasBytesAvailable: {  
  7.               
  8.               
  9.             uint8_t buf[100] = {0};  
  10.             int numBytesRead = [(NSInputStream *)stream read:buf maxLength:100];  
  11.               
  12.             NSString* str = [NSString stringWithFormat:@"recv: %s", buf];  
  13.               
  14.             UILocalNotification* n = [[[UILocalNotification alloc] init] autorelease];  
  15.             [n setAlertBody:[NSString stringWithFormat:@"notify: %x", stream]];  
  16.             [[UIApplication sharedApplication] presentLocalNotificationNow:n];  
  17.             break;  
  18.         }  
  19.               
  20.         case NSStreamEventErrorOccurred: {  
  21.               
  22.             break;  
  23.         }  
  24.               
  25.         case NSStreamEventEndEncountered: {  
  26.               
  27.               
  28.             break;  
  29.         }  
  30.               
  31.         default:  
  32.             break;  
  33.     }  
  34. }  

收到数据后,显示一条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的属性,如

  1. [readStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType];  


这样,当程序切到后台的时候,这个socket连接还会被保持。上面的示例代码里面有2个连接,一个采用了voip属性,另外一个没有。

这样的话,当这个程序切到后台后,只有voip属性的那个socket还有效,另外一个将会失效。我测试了一下,确实是这样的。

另外,iphone都是通过wifi或者gprs上网的,那么当socket连接空闲一段时间后,这个连接有可能被路由器关闭,为了保持连接,我们需要不停发送心跳包。


由于iphone上的程序切到后台后,程序会被挂起,那么也就无法定时发送心跳包,所以这个问题只能由服务端来解决。普通的办法就是服务器每隔一定时间给每个客户端发送一个心跳包,以维持这个连接。每当客户端接收到心跳包的时候,客户端会被IOS唤醒,获得一小段CPU时间,然后再次进入挂起状态。

相关测试代码:http://download.csdn.net/detail/zj510/5390813

抱歉!评论已关闭.