Почему не вызываются методы библиотеки (делегата)? CocoaAsyncSocket

Я застрял в этой проблеме уже несколько дней и, кажется, приближаюсь к решению (с помощью замечательных пользователей @ SO). Я использую библиотеку CocoaAsyncSocket для создания подключения через сокет TCP к серверу Windows.

Соединение выполняется в моем appDelegate:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    socket = [[AsyncSocket alloc] initWithDelegate:self];
    NSError *error = nil;
    if (![socket connectToHost:@"199.5.83.63" onPort:11005 error:&error]) 
    {
        NSLog(@"Error connecting: %@", error);
    }

    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    self.viewController = [[[tekMatrixViewController alloc] initWithNibName:@"tekMatrixViewController" bundle:nil] autorelease];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}

У меня есть метод подключения (часть библиотеки), называемый onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port:

- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
    NSLog(@"connected :D");
}

Этот метод вызывается, так как я вижу вывод из NSLOG и успешно подключаюсь. Я также вижу успешное подключение с компьютера с Windows (используя файлы журнала).

Я также проверил, что вызывается другой метод делегата :

- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
    NSLog(@"error - disconnecting");
    // start reconnecting procedure here...
}

Я проверил, что метод willDisconnectWithError работает, запустив мое приложение в симуляторе, а затем отключив сетевой шнур от ноутбука. Как только я это сделал, я увидел в своем выводе строку «ошибка - отключение».

Однако большая проблема заключается в том, что мой метод делегата (опять же, из библиотеки) не вызывается.

Метод делегата не вызывается:

- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    NSData *strData = [data subdataWithRange:NSMakeRange(0, [data length])];
    NSString *msg = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding];
    if(msg)
    {
        NSLog(@"RX:%@",msg);
    }
    else 
    {
        NSLog(@"Fail");
    }    
}

Я уверен в своих знаниях и понимании того, как работают методы делегирования, но я все еще не совсем понимаю, КАК они ВЫЗЫВАЮТСЯ. Чтобы еще больше усложнить и вызвать путаницу, один метод делегата (onSocket: порт didConnectToHost:) вызывается, а другой (onSocket: тег didReadData:) не вызывается. К сожалению, это только первый шаг моей проблемы, но мне нужно исправить эту проблему, прежде чем я перейду к другой проблеме.

Любая помощь будет принята с благодарностью. Спасибо


person Skizz    schedule 07.06.2012    source источник
comment
Как реализован ваш сервер Windows? Я спрашиваю, потому что некоторые «серверы» не отправляют данные, пока их буфер не заполнится или пока они не получат символы CR & LF или CR. Итак: вы абсолютно уверены, что ваш сервер отправляет данные? Вы всегда можете проверить это, подключившись к нему по телнету.   -  person Rok Jarc    schedule 07.06.2012
comment
Между прочим, если вы хотите понять, как вызываются методы делегата, посмотрите на исходный код в AsyncSocket.m — строки с 3782 по 3785 точно показывают, как вызывается onSocket:didReadData:withTag:.   -  person glorifiedHacker    schedule 08.06.2012
comment
И еще вариант, что ваши данные не являются строкой UTF8. Попробуйте добавить NSLog ("RX length: %d", [data length]); перед if(msg). Какие результаты вы получаете? Конечно, это будет иметь смысл только тогда, когда вам удастся вызвать его.   -  person Rok Jarc    schedule 08.06.2012
comment
@rokjarc msg будет либо что-то, либо nil, третьего варианта нет, поэтому его блок if-else будет выполняться так или иначе.   -  person glorifiedHacker    schedule 08.06.2012
comment
@glorifiedHacker: да, msg будет что-то или ноль. Я говорю о data. msg может быть нулевым, если data не закодирован в UTF8 - это не означает, что соединение не работает.   -  person Rok Jarc    schedule 08.06.2012
comment
@Skizz: попробуйте NSLog, о котором я упоминал ранее. Вы получите Fail, если данные не закодированы в UTF8. Что вы получаете за [длина данных];   -  person Rok Jarc    schedule 08.06.2012
comment
@rokjarc Я перечитал ваш комментарий и раньше неправильно понял ваш смысл. Извини за это!   -  person glorifiedHacker    schedule 08.06.2012
comment
Без проблем. Однажды я видел точно такую ​​​​же ситуацию, поэтому я думаю, что это может быть (помимо прочего) проблема UTF8.   -  person Rok Jarc    schedule 08.06.2012
comment
@rokjarc Я попробовал упомянутый вами NSLog, и вот что я получаю в своем выводе: 2012-06-08 13:17:30.815 tekMatrix[2793:f803] RX length: 8   -  person Skizz    schedule 08.06.2012
comment
Хорошо, это означает, что ваше соединение работает, и данные не могут быть закодированы в UTF8. Вы можете попробовать распечатать данные в шестнадцатеричном формате или что-то в этом роде, чтобы увидеть, что вы на самом деле получаете. Хороший пример того, как это сделать, находится здесь: stackoverflow.com/questions/1305225/   -  person Rok Jarc    schedule 08.06.2012
comment
О чувак. Я уже создавал подобный вопрос. Я проверю сообщение SO, которое вы оставили здесь, и попытаюсь найти решение таким образом. Всем спасибо за помощь и быстрые ответы :)   -  person Skizz    schedule 08.06.2012


Ответы (2)


Из файла AsyncSocket.h:

/**
 * Called when a socket has completed reading the requested data into memory.
 * Not called if there is an error.
**/
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;

Мое первое предположение заключается в том, что у вас есть ошибка, и поэтому ваш метод делегата не вызывается. Вы также реализовали метод делегата для обработки ошибок?

/**
 * In the event of an error, the socket is closed.
 * You may call "unreadData" during this call-back to get the last bit of data off the socket.
 * When connecting, this delegate method may be called
 * before"onSocket:didAcceptNewSocket:" or "onSocket:didConnectToHost:".
**/
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err;

ПРИМЕЧАНИЕ. Тот факт, что вы можете подключиться без ошибок, не означает, что вы сможете читать без ошибок. Аргумент ошибки, который вы передаете в connectToHost:onPort:error:, не охватывает все ошибки.

РЕДАКТИРОВАТЬ: Не могли бы вы опубликовать часть кода, в которой вы вызываете один из методов «readData» в сокете? Там может быть что-то, что упускается из виду. Если, например, в сокет не отправляется сообщение «readData», это объясняет, почему ваш метод делегата не вызывается.

РЕДАКТИРОВАТЬ: метод onSocket:didReadData:withTag: будет вызываться только после того, как вы вызвали один из следующих методов readData в сокете. Например:

// The readData and writeData methods won't block (they are asynchronous).
// 
// When a read is complete the onSocket:didReadData:withTag: delegate method is called.
// When a write is complete the onSocket:didWriteDataWithTag: delegate method is called.
// 
// You may optionally set a timeout for any read/write operation. (To not timeout, use a negative time interval.)
// If a read/write opertion times out, the corresponding "onSocket:shouldTimeout..." delegate method
// is called to optionally allow you to extend the timeout.
// Upon a timeout, the "onSocket:willDisconnectWithError:" method is called, followed by "onSocketDidDisconnect".
// 
// The tag is for your convenience.
// You can use it as an array index, step number, state id, pointer, etc.

/**
 * Reads the first available bytes that become available on the socket.
 * 
 * If the timeout value is negative, the read operation will not use a timeout.
**/
- (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag;
person glorifiedHacker    schedule 07.06.2012
comment
Да, реализовано willDisconnectWithError. Я проверил это, отсоединив кабель Ethernet от моего ноутбука, когда я запускаю свое приложение в симуляторе. Я обновлю свой исходный пост дополнительными методами делегирования, которые я реализовал. Спасибо за быстрый ответ! - person Skizz; 07.06.2012
comment
Честно говоря, я даже не уверен, как вызываются/вызываются didConnectToHost и didDisconnectWithError. Если мой метод didReadData не вызывается/не вызывается, то как мне его вызвать/вызвать? - person Skizz; 08.06.2012
comment
Я отредактировал свой ответ выше, указав более подробную информацию из заголовочного файла AsyncSocket. Где-то в вашем коде вы должны вызывать что-то вроде: [socket readDataWithTimeout:10 tag:1234567890]; - person glorifiedHacker; 08.06.2012
comment
Потрясающий! Мой метод вызывается сейчас. Хотя мой метод возвращает строку Fail в моем выводе, но, по крайней мере, он вызывается. Большое спасибо за помощь и быстрые ответы! - person Skizz; 08.06.2012
comment
Пожалуйста. Я определенно рекомендую взглянуть на исходный код AsyncSocket, поскольку он поможет вам понять, что в методах делегата нет ничего волшебного — только причина и следствие. - person glorifiedHacker; 08.06.2012

Я столкнулся с аналогичной проблемой, когда метод didReadData() в моем клиентском приложении не вызывался после того, как мое серверное приложение отправило установленные данные через [newSocket writeData:welcomData withTimout:-1 tag:1].

Моя проблема была решена после того, как я вставил следующую строку в метод didConnectToHost(). [clientAsyncSocket readDataToData: [GCDAsyncSocket CRLFData] withTimeout: -1.0 tag:0];

Теперь метод didReadData() моего клиента вызывается соответствующим образом всякий раз, когда содержимое отправляется в нужное место.

person MarkMendy    schedule 10.12.2019