0

CocoaAsyncSocketで半動作する単純なクライアントおよびサーバーアプリケーションがあります。クライアントを使用してサーバーに接続でき、クライアント間でデータをやり取りできます。デリゲートメソッドは正しく起動しているようです。私の問題は、デリゲートメソッドの1つに渡される(AsyncSocket *)オブジェクトにのみデータを送り返すことができることです。接続を受け入れるときに、ソケットをNSMutableArrayに追加しますが、後でソケットを使用しようとすると、書き込みが失敗します。それで

[connectedSockets addObject:newSocket];
//then later
[[connectedSockets objectAtIndex:i] writeData:someData withTimeout:-1 tag:0];

動作しません。サーバーとクライアントのコードは以下のとおりです。最初の通信は機能しますが、通知が呼び出されると、NSLogステートメントがアレイ内のソケットをテストし、適切なIPアドレスとポート番号を取得してもデータは送信されません。

サーバ:

- (id)init
{
    self = [super init];
    if (self) {
        listenSocket = [[AsyncSocket alloc] initWithDelegate:self];
        [listenSocket setRunLoopModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
        [listenSocket acceptOnPort:42381 error:nil];


        connectedSockets = [[NSMutableArray alloc] init];
        newNotificationDictArray = [[NSMutableArray alloc] init];
        updateNotificationDictArray = [[NSMutableArray alloc] init];

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(newJobNotification:)
                                                     name:@"NewJob"
                                                   object:nil];
    }

    return self;

}

-(void)onSocketDidDisconnect:(AsyncSocket *)sock
{
    [connectedSockets removeObject:sock];
}

- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
    [connectedSockets removeObject:sock];
}

- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
{
    [connectedSockets addObject:newSocket];
}


- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
if ([newNotificationDictArray count] > 0) {
    NSMutableData *data = [[NSMutableData alloc] init];
    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    [archiver encodeObject:newNotificationDictArray forKey:@"DictArray"];
    [archiver finishEncoding];
    [archiver release];
    [sock writeData:data withTimeout:-1 tag:0];
    [data release];
}

[sock readDataWithTimeout:-1 tag:0];
}

- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
    [sock readDataWithTimeout:-1 tag:0];
}

- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
[sock readDataWithTimeout:-1 tag:0];
}

-(void) newJobNotification: (NSNotification *) notification
{
NSDictionary *dict = [notification userInfo];
[newNotificationDictArray addObject:dict];
[updateNotificationDictArray addObject:dict];
NSMutableData *updateData = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:updateData];
[archiver encodeObject:updateNotificationDictArray forKey:@"DictArray"];
[archiver finishEncoding]
[updateNotificationDictArray removeAllObjects];
[archiver release];
NSLog(@"Attempting to write to %@:%i", [[connectedSockets objectAtIndex:0] connectedHost], [[connectedSockets objectAtIndex:0] connectedPort]) 
[[connectedSockets objectAtIndex:0] writeData:updateData withTimeout:-1 tag:0];
}

そしてクライアント:

- (id)init
{
self = [super init];
if (self) {
    socket = [[AsyncSocket alloc] initWithDelegate:self];
}
return self;
}

-(void) connectToHost: (NSString *) address
{

}

-(BOOL)onSocketWillConnect:(AsyncSocket *)sock 
{
[sock retain];
[socket readDataWithTimeout:-1 tag:0];
return YES;
}

-(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port 
{    
NSLog(@"Did Connect on port %i", [sock connectedPort]);
}

-(void) disconnectFromRemoteHost
{
[socket disconnect];
}

-(void)onSocketDidDisconnect:(AsyncSocket *)sock
{
NSLog(@"Did Disconnect");
}

- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
NSLog(@"Disconnect Error: %@", [err localizedDescription]);
}

- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
[socket readDataWithTimeout:-1 tag:0];
}

- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    NSArray *dictArray = [[unarchiver decodeObjectForKey:@"DictArray"] retain];
    [unarchiver finishDecoding];
    [unarchiver release];
    for (NSDictionary *dict in dictArray) {
        if ([[dict objectForKey:@"Kind"] isEqualTo:@"New"])
            [[NSNotificationCenter defaultCenter] postNotificationName:@"NewJob" object:self userInfo:dict];
        else if ([[dict objectForKey:@"Kind"] isEqualTo:@"Update"])
            [[NSNotificationCenter defaultCenter] postNotificationName:@"JobUpdate" object:self userInfo:dict];
    }
[socket readDataWithTimeout:-1 tag:0];
}

私のstackoverflowを助けてください、あなたは私の唯一の希望です!

4

1 に答える 1

1

投稿されたコードに2つの潜在的な問題があります。最初のものはあなたの問題を引き起こしている可能性は低いようですが、とにかくそれを投稿します。クライアントコードには次のものがあります。

-(BOOL)onSocketWillConnect:(AsyncSocket *)sock 
{
    [sock retain];
    [socket readDataWithTimeout:-1 tag:0];
    return YES;
}

なぜここで「靴下」を保持するのかわかりません。作成したソケットのコピーがすでに保持されているため、リークが発生する可能性があります。

あなたの失敗の原因である可能性が高い2番目の問題については、これが私が起こっていると思うことです。AsyncSocketのドキュメントを見ると、次のようになっています。

ただし、AsyncSocketはスレッドセーフではありません。ソケットが構成されているスレッド/実行ループからのみAsyncSocketのメソッドを呼び出す必要があります。AsyncSocketが実行されているスレッドとは異なるスレッドを見つけ、AsyncSocketでメソッドを呼び出す必要がある場合は、performSelector:onThread:のようなメソッドを使用して、メソッドがAsyncSocketのスレッドで呼び出されるようにする必要があります(そしてそれによってスレッドセーフを維持します)。

通知を受信して​​「後の」書き込みをトリガーするコードは、別のスレッドにある可能性が高いため、スレッドが有効であっても、書き込みは期待どおりに実行されません。AsyncSocketのドキュメントには、スレッドセーフが必要な場合にGCDAsyncSocketを使用することが推奨されています。

于 2011-08-22T23:38:22.187 に答える