iOS 上的 VoIP 套接字 - 未收到通知
Posted
技术标签:
【中文标题】iOS 上的 VoIP 套接字 - 未收到通知【英文标题】:VoIP socket on iOS - no notifications received 【发布时间】:2012-08-21 14:30:43 【问题描述】:我有一个 VoIP 应用程序,它使用 TCP 服务在来电时唤醒它。 TCP 套接字是使用以下代码片段创建的:
CFReadStreamRef read = NULL;
CFWriteStreamRef write = NULL;
...
CFStreamCreatePairWithSocketToHost(NULL,(__bridge CFStringRef)shost, port, &read, &write);
self.read = (__bridge NSInputStream*)read;
self.write = (__bridge NSOutputStream*)write;
if (![self.read setProperty:NSStreamNetworkServiceTypeVoIP
forKey:NSStreamNetworkServiceType])
[Log log:@"Could not set VoIP mode to read stream"];
if (![self.write setProperty:NSStreamNetworkServiceTypeVoIP
forKey:NSStreamNetworkServiceType])
[Log log:@"Could not set VoIP mode to write stream"];
self.read.delegate = self;
self.write.delegate = self;
CFRelease(read);
CFRelease(write);
[self.read scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[self.write scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[self.read open];
[self.write open];
我还设置了以下内容:
-
信息列表中的 VoIP 和音频
使用 [UIApplication sharedApplication] setKeepAliveTimeout 保持活动计时器
UIRequiresPersistentWiFi = YES 在 info plist 中(很确定它不是必需的,但是...)
这在应用程序在前台运行良好,甚至在后台运行几分钟,但几分钟后 - 应用程序没有收到任何新的 TCP 消息。 它不适用于 wifi 或 3G,两者的结果相同。
我还尝试将属性设置为仅读取流(尽管读取和写入指向同一个套接字)。 每当我在 TCP 上接收数据或发送数据时,我也会启动一个简短的后台任务。 顺便说一句 - 一切都发生在主线程上。 我检查了应用程序是否崩溃 - 它没有。 在设备上调试时可以观察到相同的行为 - 一段时间后 - 没有收到任何信息(没有崩溃、警告等)。
我做错了什么?
【问题讨论】:
可能值得在 info plist 仔细检查正确的 VOIP 标志/标签... 双重和三重检查...一切正常运行一段时间然后停止。 服务器是否有可能在超时后关闭套接字?即:服务器故障而不是应用程序? 没有..wireshark服务器,消息出来了,tcp连接没有掉线。 我确定您已经检查了 VOIP 应用程序的步骤 1-6。参考::developer.apple.com/library/ios/#documentation/iphone/… 【参考方案1】:看起来您的代码应该可以工作。但我能想到的可能有两个技术问题:
如果您从 LAN 连接尝试此操作,当应用程序在后台时,LAN 路由器可以关闭被动 TCP 连接,因为在这种情况下,SIP 堆栈(猜测您使用 SIP 协议)无法每 15 次发送数据保持活动状态到 30 秒,就像在前台一样。
不太可能,假设您知道自己在做什么,但是由于注册保持活动在后台只能在 10 分钟内触发一次,因此请确保 SIP 服务器允许如此长的过期时间,并且您在注册消息。
【讨论】:
感谢您的回答-我没有检查 LAN,而且我知道 TCP 的方式我认为这不是问题,但我的问题确实与 3G 相关,因为该应用程序适用于户外使用。无论如何 - 该应用程序不使用 SIP,它使用我在 10 多年前为 Brew 平台构建的专有 VoIP 协议……服务器在 10 分钟间隔内没有问题,我可以看到消息发出,只是不进去...... 虽然你的回答没有帮助 - 你得到了努力并尝试跳出框框思考的赏金。 10 倍! 谢谢。第一个问题肯定发生在某些路由器上,我个人在使用 TCP 连接的基于 SIP 的 iOS 应用程序中体验过。由于连接速度慢和运营商相关的问题,3G 可能会出现更多问题。我建议使用不同的 3G(运营商)测试您的应用,看看在行为上是否有任何差异。【参考方案2】:尝试以下代码。确保您的应用中只有一个 voip 套接字。
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"1.2.3.4",9999, &readStream, &writeStream);
CFReadStreamSetProperty(readStream,kCFStreamNetworkServiceType,kCFStreamNetworkServiceTypeVoIP);
CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);
inputStream = (NSInputStream *)readStream;
[inputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
outputStream = (NSOutputStream *)writeStream;
[outputStream setDelegate:self];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream open];
【讨论】:
请不要要求用户或原始发帖人在答案中查看您自己的问题 - 这更适合发表评论。 谢谢,据我所知,您刚刚切换了订单并使用 CFReadStreamSetProperty 而不是 setProperty: 。无论如何 - 以防万一 - 相同的结果。哦,我只有一个 VoIP 插座。【参考方案3】:在ViewController.h
文件中添加
@property (nonatomic, strong) NSInputStream *inputStream;
@property (nonatomic, strong) NSOutputStream *outputStream;
@property (nonatomic) BOOL sentPing;
在ViewController.m
文件中添加@implementation ViewController
之后
const uint8_t pingString[] = "ping\n";
const uint8_t pongString[] = "pong\n";
在viewDidLoad
中添加如下代码
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)(@"192.168.0.104"), 10000, &readStream, &writeStream);
//in above line user your MAC IP instead of 192.168.0.104
self.sentPing = NO;
//self.communicationLog = [[NSMutableString alloc] init];
self.inputStream = (__bridge_transfer NSInputStream *)readStream;
self.outputStream = (__bridge_transfer NSOutputStream *)writeStream;
[self.inputStream setProperty:NSStreamNetworkServiceTypeVoIP forKey:NSStreamNetworkServiceType];
[self.inputStream setDelegate:self];
[self.outputStream setDelegate:self];
[self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.inputStream open];
[self.outputStream open];
//After every 10 mins this block will be execute to ping server, so connection will be live for more 10 mins
[[UIApplication sharedApplication] setKeepAliveTimeout:600 handler:^
if (self.outputStream)
[self.outputStream write:pingString maxLength:strlen((char*)pingString)];
//[self addEvent:@"Ping sent"];
];
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
switch (eventCode)
case NSStreamEventNone:
// do nothing.
break;
case NSStreamEventEndEncountered:
//[self addEvent:@"Connection Closed"];
break;
case NSStreamEventErrorOccurred:
//[self addEvent:[NSString stringWithFormat:@"Had error: %@", aStream.streamError]];
break;
case NSStreamEventHasBytesAvailable:
if (aStream == self.inputStream)
uint8_t buffer[1024];
NSInteger bytesRead = [self.inputStream read:buffer maxLength:1024];
NSString *stringRead = [[NSString alloc] initWithBytes:buffer length:bytesRead encoding:NSUTF8StringEncoding];
stringRead = [stringRead stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
//[self addEvent:[NSString stringWithFormat:@"Received: %@", stringRead]];
//if server response is 'call' then a notification will go to notification center and it will be fired
//immediately and it will popup if app is in background.
if ([stringRead isEqualToString:@"call"])
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = @"New VOIP call";
notification.alertAction = @"Answer";
//[self addEvent:@"Notification sent"];
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
//else if ([stringRead isEqualToString:@"ping"])
//
//if server response is 'ping' then a sting 'pong' will go to server immediately
//[self.outputStream write:pongString maxLength:strlen((char*)pongString)];
//
break;
case NSStreamEventHasSpaceAvailable:
if (aStream == self.outputStream && !self.sentPing)
self.sentPing = YES;
if (aStream == self.outputStream)
[self.outputStream write:pingString maxLength:strlen((char*)pingString)];
//[self addEvent:@"Ping sent"];
break;
case NSStreamEventOpenCompleted:
if (aStream == self.inputStream)
//[self addEvent:@"Connection Opened"];
break;
default:
break;
构建您的应用并运行
在您的 MAC PC 中打开终端并输入nc -l 10000
并按回车
$ nc -l 10000
然后写call
并回车
【讨论】:
以上是关于iOS 上的 VoIP 套接字 - 未收到通知的主要内容,如果未能解决你的问题,请参考以下文章
在没有 VoIP iOS 的情况下保持 XMPP 套接字在后台活动