【问题标题】:Server/Client not communicating correctly (CocoaAsyncSocket)服务器/客户端无法正确通信(CocoaAsyncSocket)
【发布时间】:2011-08-22 21:36:22
【问题描述】:

我有一个使用 CocoaAsyncSocket 的简单客户端和服务器应用程序。我可以使用客户端连接到服务器,并且可以在它们之间来回传递数据,并且委托方法似乎可以正确触发。我的问题是我只能将数据发送回传递给委托方法之一的 (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,你是我唯一的希望!

【问题讨论】:

  • 我们在这里谈论多少“以后”?是否有可能由于超时而关闭连接?
  • 在测试期间,可能需要 15-30 秒(尽管实际使用时间会更长)。我没有收到任何类型的断开连接日志语句。

标签: objective-c cocoa network-programming cocoaasyncsocket


【解决方案1】:

我发现您发布的代码存在 2 个潜在问题。第一个似乎不太可能导致您的问题,但无论如何我都会发布它。在您的客户端代码中,您有:

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

我不确定您为什么要在此处保留“袜子”。您已经保留了您创建的套接字的副本,这似乎可能导致泄漏。

至于第二个问题,这更有可能是您失败的原因,这就是我认为正在发生的事情。查看 AsyncSocket 的文档,我看到了这一点:

但是,AsyncSocket 不是线程安全的。您只能调用 AsyncSocket 上的方法 配置套接字的线程/运行循环。如果你发现自己在一个线程上 与运行 AsyncSocket 的线程不同,您需要调用 AsyncSocket 上的方法,那么您必须使用像 performSelector:onThread: 这样的方法来确保 该方法在 AsyncSocket 的线程上调用(从而维护线程安全)。

您的接收通知并触发“稍后”写入的代码可能在另一个线程中,因此即使线程有效,写入也无法达到您的预期。如果您想要线程安全,AsyncSocket 文档继续建议您使用 GCDAsyncSocket。

【讨论】:

  • 就是这样,我将项目切换到 GCDAsyncSocket 并且一切正常!我也摆脱了内存泄漏。非常感谢您的帮助!
猜你喜欢
  • 2017-01-07
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 2018-01-03
  • 1970-01-01
  • 2011-04-28
  • 1970-01-01
相关资源
最近更新 更多