9

TCPサービスを使用して着信時にウェイクアップするVoIPアプリがあります。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];

また、次のように設定しました。

  1. 情報plistのVoIPとオーディオ
  2. [UIApplicationsharedApplication]setKeepAliveTimeoutを使用してキープアライブタイマー
  3. 情報plistのUIRequiresPersistentWiFi=YES(必須ではないことを確認してくださいが...)

これは、アプリがフォアグラウンドにある間はうまく機能し、バックグラウンドでも数分間はうまく機能しますが、数分後、アプリは新しいTCPメッセージを受信しません。Wi-Fiまたは3Gでは機能せず、どちらも同じ結果になります。

また、プロパティを読み取りストリームのみに設定してみました(ただし、読み取りと書き込みは同じソケットを指します)。TCPでデータを受信したり、データを送信したりするたびに、短いバックグラウンドタスクも開始します。ところで-すべてがメインスレッドで行われます。
アプリがクラッシュするかどうかを確認しましたが、クラッシュしません。
デバイスでのデバッグ中にも同じ動作が観察されます-しばらくすると-何も受信されません(クラッシュ、警告などはありません)。

私は何が間違っているのですか?

4

3 に答える 3

3

次のコードを試してください。アプリにVoIPソケットが1つしかないことを確認してください。

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];
于 2012-08-30T15:47:30.620 に答える
3

コードは機能するはずです。しかし、私が考えることができる2つの技術的な問題があるかもしれません:

  1. これをLAN接続から試してみると、アプリがバックグラウンドにある間、LANルーターはパッシブTCP接続を閉じることができます。この場合、SIPスタック(SIPプロトコルを使用していると推測されます)は、15〜30秒ごとにデータを送信してキープアライブを行うことができないためです。フォアグラウンドで。

  2. 可能性は低いですが、自分が何をしているのかを知っていると仮定しますが、登録キープアライブはバックグラウンドで10分に1回しかトリガーできないため、SIPサーバーでこのような長い有効期限が許可されていることを確認し、登録メッセージで正しく定義してください。

于 2012-11-01T10:34:26.783 に答える
0

ファイルに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てEnterキーを押します

$ nc -l 10000

次に、書き込みcall、Enterキーを押します

于 2014-09-09T08:58:26.543 に答える