AsyncSocket не вызывает делегатов - PullRequest
2 голосов
/ 05 февраля 2011

У меня странная проблема при попытке использовать 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, заключается в том, что я хотел скрыть все делегаты сокетоввещи из бизнес-логики приложения.Мне нужно использовать сокетное соединение во многих разных местах, и я не хочу реализовывать низкоуровневые функции сокетов (например, определение состояния сокета, получение заголовка сообщения, затем тела и т. Д.) Во многих разных местах.Я хочу иметь простой интерфейс, где я могу открывать / отправлять / получать и не беспокоиться о реализации низкого уровня.Я понимаю, что сетевое подключение должно выполняться в отдельном потоке, и это нормально - создание фонового рабочего в основном потоке не проблема.

Итак, я взял образец InterfaceTest из репозитория AsyncSocket в качестве отправной точки.Убрал DNS, связанный с этим материал.Работает отлично.звонил didConnect, все блестит.

Затем я добавил в проект свою реализацию SyncSocket, чтобы узнать, что с ней не так.Проект можно скачать здесь: http://dl.dropbox.com/u/6402890/NetworkTest.zip - может быть, кто-то может сказать мне, что я делаю неправильно - у меня возникло ощущение, что я не использую потоки должным образом в SyncSocket.

Если я использую в цикле ожидания и asyncSocket is Connected, и мой внутренний self.waiting - он выходит из этого цикла и вызывается didConnect (но ПОСЛЕ окончания цикла).Если я пытаюсь использовать только мой self.waiting, который установлен в didConnect - didConnect никогда не вызывается и приложение зависает.

Кто-нибудь может сказать мне, что не так?

1 Ответ

1 голос
/ 07 февраля 2011

Нашел проблему. Похоже, мне пришлось изменить цикл ожидания с помощью:

[[NSThread sleepForTimeInterval: 0.01]

Для использования RunLoop:

[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
...