2011-02-05 22 views
2

私は、AsyncSocketを使用しようとすると奇妙な問題が発生します。私のアプリでは、実際には同期ソケットが必要です。なぜなら、バックグラウンドですべての通信を別のレベルで処理するからです。だから私は、AsyncSocketクラスのSyncSocketの周りにラッパーを書き込もうとしています。AsyncSocketが代理人を呼び出さない

// SyncSocket.h 
#import <Foundation/Foundation.h> 
#import "AsyncSocket.h" 

@interface SyncSocket : NSObject <AsyncSocketDelegate> { 
    AsyncSocket* _asyncSocket; 
    NSTimeInterval _connectTimeout; 
    NSTimeInterval _readTimeout; 
    NSTimeInterval _writeTimeout; 
    BOOL _waiting; 
    BOOL _nsLog; 
} 

@property (nonatomic, assign) BOOL waiting; 
@property (nonatomic, assign) BOOL nsLog; 

- (id) initWithConnectTimeout: (NSTimeInterval) connectTimeout readTimeout: (NSTimeInterval) readTimeout writeTimeout: (NSTimeInterval) writeTimeout; 

- (BOOL) connectToHost: (NSString*) host onPort: (UInt16) port; 

@end 

// SyncSocket.m 
#import "SyncSocket.h" 

@implementation SyncSocket 
@synthesize waiting = _waiting; 
@synthesize nsLog = _nsLog; 

// 
// Constructor/destructor 
// 

- (id) initWithConnectTimeout: (NSTimeInterval) connectTimeout readTimeout: (NSTimeInterval) readTimeout writeTimeout: (NSTimeInterval) writeTimeout { 
    [super init]; 
    if (self == nil) 
     return self; 

    _connectTimeout = connectTimeout; 
    _readTimeout = readTimeout; 
    _writeTimeout = writeTimeout; 
    _waiting = NO; 

    _asyncSocket = [[AsyncSocket alloc] initWithDelegate: self]; 

    return self; 
} 

- (void) dealloc { 
    [_asyncSocket release]; 
    [super dealloc]; 
} 

- (BOOL) connectToHost: (NSString*) host onPort: (UInt16) port { 
    if (self.nsLog) 
     NSLog (@"connectToHost: %@ onPort: %d", host, port); 

    _waiting = YES; 
    NSError* err = nil; 
    if (![_asyncSocket connectToHost: host 
         onPort: port 
        withTimeout: _connectTimeout 
        error: &err]) 
     return NO; 

    while (self.waiting && [_asyncSocket isConnected] == NO) { 
     [NSThread sleepForTimeInterval: 0.01]; 
    } 


    return [_asyncSocket isConnected]; 
} 

- (void) writeData: (NSData*) data { 
    _waiting = YES; 
    [_asyncSocket writeData: data withTimeout: _writeTimeout tag: 0]; 

    while (self.waiting) { 
     [NSThread sleepForTimeInterval: 0.01]; 
    } 
} 


// 
// AsyncSocket delegates 
// 
- (BOOL)onSocketWillConnect:(AsyncSocket *)sock { 
    if (self.nsLog) 
     NSLog (@"onSocketWillConnect:"); 
    return YES; 
} 

- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag { 
    if (self.nsLog) 
     NSLog (@"didWriteDataWithTag: %d", tag); 
    _waiting = NO; 
} 

- (void) onSocket: (AsyncSocket*) sock willDisconnectWithError: (NSError*) err { 
    if (self.nsLog) 
     NSLog (@"willDisconnectWithError: %d", [err code]); 

    _waiting = NO; 
} 

- (void) onSocket: (AsyncSocket*) sock didConnectToHost: (NSString*) host port: (UInt16) port { 
    if (self.nsLog) 
     NSLog (@"didConnectToHost: %@ port: %d", host, port); 

    _waiting = NO; 
} 

@end 

問題がある:ここではコードですAsyncSocketがうまくホストに接続しますが、私のデリゲートdidConnetToHostが呼び出されることはありません。 AsyncSocketコードをデバッグすると、デリゲートがrespondsToSelectorに設定されていてもエラーが表示されます。奇妙な記憶違反や何かがあるように見えますが、私はどこでミスをしたのか分かりません。

アイデア?同期ソケットとなるようにAsyncSocketをラップする方法の良い例はありますか?

PS:明確にする:XCode 3.2.5、iPhone Simulator 4.2。

更新:SyncSocketでそれをラップしようとしているのは、アプリケーションのビジネスロジックからすべてのソケットデリゲートを隠すためです。私は多くの異なる場所でソケット接続を使用する必要があり、私は多くの異なる場所で低レベルのソケット関数(ソケットの状態の検出、メッセージのヘッダーの受信など)を実装したくありません。私はオープン/送信/受信が可能で、低レベルの実装について心配しないシンプルなインターフェースを持ちたいと思っています。私は、ネットワーク接続を別のスレッドで実行する必要があることを理解しています。これはうまくいきます。メインスレッドの1人のバックグラウンドワーカーは問題ではありません。

私は出発点としてAsyncSocketリポジトリからInterfaceTestサンプルを取得しました。そこからDNS関連のものが削除されました。正常に動作します。 didConnectが呼び出され、すべてが光っています。

次に私のSyncSocket実装にプロジェクトを追加して、何が問題なのかを確認しました。プロジェクトはここからダウンロードできます:http://dl.dropbox.com/u/6402890/NetworkTest.zip - 誰かが私が間違っていることを教えてくれるかもしれません - 私はSyncSocketでスレッドを正しく使用していないと感じています。

私が待機ループで使用する場合、asyncSocket is Connectedと私の内部self.waiting - それはそのループから抜け出し、が呼び出されます(しかし、ループが終了した後)。 didConnectで設定されているself.waitingだけを使用しようとすると、didConnectが呼び出されず、アプリケーションがハングします。

何が間違っているか教えていただけますか?

+0

任意の違いを確認しなかったこと。不思議なこと - connectメソッドを呼び出した後 - onSocketWillConnectが呼び出されてから何もしません。 isConnectedがTRUEになるので、私はループから脱出しています。 – sha

+0

あなたのinitメソッドを変更する:if(self = [super init]){/ * initialization * /} selfを返す。 – Felix

+0

試しました。何も変更しません。それは私が理解していたものと同等です。 – sha

答えて

1

問題が見つかりました。私が使用してからループを待って変更しなければならなかったように見える:

[[NSThread sleepForTimeInterval: 0.01] 

実行ループを使用して:

[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]; 
+0

私はちょうど2日間同じ問題で立ち往生していたので、お礼を言いたいと思います。これはGCDAsyncSocketsのどこにも言及されておらず、初心者にとっては非常に混乱しています。私のコードは正常に実行されますが、デリゲートは、ソケットが切断され、デリゲートキューがnullに設定された後にのみ呼び出されます。再び、ありがとう、あなたは私の日を救った! –

+0

問題はありません:)喜んで他の誰かを助けました – sha