11

ソケットにデータを書き込む次のコードを Objective-C で記述しています。サーバーは、Ubuntu の上で node.js を実行しています。

NSString *url = @"anIPAddress";        
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;            
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)url, 9000, &readStream, &writeStream);
self.inputStream = (NSInputStream *)readStream;            
self.outputStream = (NSOutputStream *)writeStream;
[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];

サーバーに接続して情報を送信できます。しかし、数分後に接続がタイムアウトすることに気付きました (5 分ほどだと思いますか?)。この接続を維持するにはどうすればよいですか? ターミナルでサーバーに接続すると同じことが起こるため、切断があることはわかっています。その接続を維持する必要があります。私のコードでも同じことが起こっていると思います。ご協力いただきありがとうございます!

4

4 に答える 4

6

最も簡単な答えは、SO_KEEPALIVEsocket オプションを使用することです。

切断された接続は、エンドポイント間でデータが流れていないと検出するのが難しい場合があります。これは、切断された接続を検出するためにデータを使用しないため、このオプションがいくつかの点で役に立たない理由です。ただし、コードに追加して表示するのは簡単です。それを追加して、それが役立つかどうかを確認してください...

これは、CまたはC++で行われる方法です

int opt = 1;
// Get the native socket handle from your socket class here...
int socket_handle = getNativeSocketHandle( self.outputStream );

/*Enabling keep alive*/
if( setsockopt( socket_handle, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof( opt ) ) < 0 )
{
   // failed setting socket option
}

それほど単純ではない答えはping、プロトコルにパケットを追加し、その ping パケットを定期的に送信して、切断された接続を検出できるようにすることです。

于 2012-07-08T23:58:05.050 に答える
3

NSOutputStream*oStreamを想定しています。

iOSでは、次のようにします。

#if 1 // Using CF
CFDataRef data = (CFDataRef)CFWriteStreamCopyProperty((__bridge CFWriteStreamRef)oStream, kCFStreamPropertySocketNativeHandle);
if(data) {
    CFSocketNativeHandle socket_handle = *(CFSocketNativeHandle *)CFDataGetBytePtr(data);
    CFRelease(data);
#else // Using Foundation
NSData *data = (NSData *)[oStream propertyForKey:(__bridge NSString *)kCFStreamPropertySocketNativeHandle];
if(data) {
    CFSocketNativeHandle socket_handle = *(CFSocketNativeHandle *)[data bytes];
#endif
    NSLog(@"SOCK HANDLE: %x", socket_handle);

    /*Enabling keep alive*/
    if( setsockopt( socket_handle, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof( opt ) ) < 0 )
    {
       NSLog(@"Yikes 2: failed to set keepalive! ERRNO: %s", strerror(errno));
    }

私はそれをすべて解決するのに何時間も費やしたので、これを投稿しています。他の誰かの労力を節約したいです。

于 2013-02-10T23:32:25.787 に答える
3

これを行う方法を見つけました。サーバーはnode.jsを実行しているので、使用しました

socket.setKeepAlive(true, 2000);

このようにして、ノードは各ソケットを開いたままにします。デフォルトは false です。これがタイムアウトの原因です。これが他の人に役立つことを願っています。回答ありがとうございます。ハートビートを維持する (キープアライブ) ことも良い考えだと思いますが、このネイティブ アプローチではノードがそれを処理します。

于 2012-07-11T04:44:53.643 に答える
3

接続を介して定期的にゴミを送信する必要があります。これを試して:

NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:240 target:self selector:@selector(timerMethod:) userInfo:[NSNumber numberWithInt:sockfd] repeats:YES];

次に、これを次のように宣言しselfます。

-(void)timerMethod:(NSTimer*)t
{
  send([[t userInfo] intValue], "Keepalive!", 11, 0);
}

注: 「キープアライブ!」を置き換えます。プロトコルに必要なものは何でも。唯一の要件は、リモート エンド (ソケット サーバー) がメッセージを無視することです。

于 2012-07-09T00:05:02.947 に答える