5

サーバーでストリームをセットアップするために、次のコードを作成しました。

-(void)streamOpenWithIp:(NSString *)ip withPortNumber:(int)portNumber;
{
       CFReadStreamRef readStream;
       CFWriteStreamRef writeStream;
       CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (__bridge CFStringRef)ip, portNumber, &readStream, &writeStream);

       if(readStream && writeStream)
       {
            CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
            CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);

            //Setup inpustream
            inputStream = (__bridge NSInputStream *)readStream;
            [inputStream setDelegate:self];
            [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [inputStream open];

            //Setup outputstream
            outputStream = (__bridge NSOutputStream *)writeStream;
            [outputStream setDelegate:self];
            [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
            [outputStream open];
       }
}

サーバーに接続してデータを送受信できます。しかし、接続がまだ存在するかどうかを確認したい。Wi-Fi ルーターからケーブルを外しても、ストリームでデータを送信でき、エラーは発生しませんでした。

タイマーを使用してメッセージを送信し、何かを受信したかどうかを確認することで、アプリケーション レベルでこれを解決できます。ただし、これは、下位レベルの TCP Keep-Alive テクニックでも解決できます。

これを NSStream で実装するにはどうすればよいですか? チェック間隔を設定するにはどうすればよいですか?

TCPキープアライブでチェックしてストリームがダウンしたときにNSStreamEventErrorOcurredを取得すると思いますか?

この投稿を確認しましたが、わかりません: iOS でソケット接続を維持する

ご協力いただきありがとうございます!

4

2 に答える 2

12

ネイティブソケットハンドルを取得できます

CFDataRef socketData = CFReadStreamCopyProperty((__bridge CFReadStreamRef)(inputStream), kCFStreamPropertySocketNativeHandle);
CFSocketNativeHandle socket;
CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&socket);
CFRelease(socketData);

次に、ソケットオプションを設定します(これには必要です#include <sys/socket.h>):

int on = 1;
if (setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1) {
   NSLog(@"setsockopt failed: %s", strerror(errno));
}

このコードをイベントのイベント ハンドラー関数に入れることができますkCFStreamEventOpenCompleted

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)event {
    switch (event) {
        case kCFStreamEventOpenCompleted:
            if (stream == self.inputStream) {
                CFDataRef socketData = CFReadStreamCopyProperty((__bridge CFReadStreamRef)(stream), kCFStreamPropertySocketNativeHandle);
                CFSocketNativeHandle socket;
                CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&socket);
                CFRelease(socketData);

                int on = 1;
                if (setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1) {
                    NSLog(@"setsockopt failed: %s", strerror(errno));
                }
            }
            break;

        /* ... other cases ... */;
    }
}
于 2013-04-03T12:14:05.480 に答える
0

同様の質問に対するより完全な回答があります。

10 秒後にキープアライブの送信を開始し、2 秒ごとにケップアライブを送信し、応答なしで 4 回のキープアライブ後にストリームを閉じるアプリの例については、次の投稿を参照してください 。Apple iOS デバイスで TCP キープアライブを有効にすることは可能ですか

また、接続が閉じられた後の再送信タイムアウトを設定する方法も示します。

于 2015-12-15T15:22:27.563 に答える