2015-03-26 2 views
1

Я пытаюсь настроить сервер Java, разговаривающий с клиентом iPhone, используя GCDAsyncSocket. По какой-то причине мой клиентский код на iPhone не считывает все данные.GCDAsyncSocket didReadData только получает вызов один раз

Я вижу, что didReadData вызывается в первый раз, но больше никогда. В идеале мне нужно подражать функциональности HTTP-протокола, где он отправляет заголовок, а затем полезную нагрузку. Размер полезной нагрузки будет в заголовке. Но это не сработало, поэтому я еще больше упростил свой код в надежде найти проблему. Ниже приведен код, а ниже - вывод.

клиент:

- (BOOL) sendString:(NSString *) string 
{ 
[asyncSocket writeData:[string dataUsingEncoding:NSUTF8StringEncoding] 
withTimeout:-1 tag:TAG_PAYLOAD]; 

[asyncSocket readDataToLength:1 withTimeout:(-1) tag:TAG_HEADER]; 
} 

- (void) socket:(GCDAsyncSocket *) sock didReadData:(NSData *)data 
withTag:(long)tag 
{ 
NSString *str = [[NSString alloc] initWithData:data 
encoding:NSUTF8StringEncoding]; 
NSLog(@"Read data %@ with tag: %ld", str, tag); 
if(tag == TAG_HEADER) 
{ 
    //TODO - parse the header, get the fields 
    [sock readDataToLength:3 withTimeout:-1 tag:TAG_PAYLOAD]; 
    //[sock readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 
    tag:TAG_PAYLOAD]; 
} 
else 
{ 
    NSLog(@"Payload... %@", str); 
    NSLog(@"Tag: %ld", tag); 
} 
} 

Java сервер:

BufferedReader in = new BufferedReader(new  InputStreamReader(clientSocket.getInputStream())); 
PrintWriter out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream())); 

String clientCommand = in.readLine(); 
System.out.println("Client Says :" + clientCommand); 
out.println("Andrew\r\nAUSTIN\r\n"); 
out.flush(); 

Однако, на клиенте, то единственное, что я получаю обратно А. Точный результат: чтения данных А с тегом: 10

Мой вопрос:

  1. Почему метод didReadData никогда не вызывается снова? Должно быть больше «Andrew \ r \ nAustin» возвращено на клиенте. Но это просто зависает. ReadDataToData и readDataToLength оба, похоже, никогда не получают полную строку.
  2. Я заметил, что CRLF определен в GCDAsyncSocket.h не \ r \ n, а вместо этого шестнадцатеричные значения. Это имеет значение? Вот почему я попробовал метод readDataToLength, но все еще не удалось. Но я хотел бы знать, имеет ли это кроссплатформенность или нет.

Спасибо.

ответ

2

OK - так что я понял это, вытащив из себя какие-то волосы, которые у меня остались.

Что происходит, так это то, что у меня есть клиентский код выше в отдельном классе за пределами представления. Практически во всех примерах, с которыми я столкнулся, был материал GCDAsyncSocket, обработанный внутри представления. Он отлично работает там! Я действительно не хотел этого делать, потому что в каждом представлении мне нужно было отправлять/читать данные и не хотеть дублировать мою работу. Поместив строку NSLog() в метод dealloc этого вспомогательного класса, называемый SocketComm, я смог увидеть, что он освобождается, прежде чем он начнет стрелять. Поэтому мне нужно было изменить способ, которым я называл свой вспомогательный класс. Я объявляю SocketComm * sockComm сильное свойство в файле viewController.h и выделял его в методе viewDidLoad(). Это означает, что он остается в сфере действия все время. Конечно, это означает, что мне нужно освободить его вручную и сделать некоторые другие вещи для домашнего хозяйства.

Я все еще не уверен, что это лучший способ справиться с этой ситуацией, насколько это касается управления памятью. Потому что теперь мне придется выделить это для каждого метода viewDidLoad. Похоже, это должно быть проще, чем здесь, но мы здесь. И я до сих пор не знаю, почему он никогда не читал данные в первый раз (я полагаю, что библиотека GCDAsyncSocket или программное обеспечение iphone обнаружила мертвый поток, когда родитель, который его породил, получил освобождение и решил его прекратить, но это только догадка, поскольку я только что начал цель-с).

Это также объясняет, почему иногда это сработает, а иногда и нет. Казалось, что это было в гонке. Не уверен, что вышеприведенный код, который я изначально опубликовал, привел к точному состоянию гонки, но некоторые вещи, которые я попытался бы, будут работать, а затем в следующий раз сработают. Он никогда не читал больше, чем в первый раз, хотя, и только примерно в половине случаев он даже прочитал бы это. Иногда он даже не посылал данные через сокет!

Суммируя (и для того, кто еще приходит ищет ответ):

  1. Всегда проверяйте управление памятью. Я должен был разместить NSLog в dealloc() класса помощника SocketComm, чтобы полностью увидеть, что происходит, и как только я это сделал, я знал, что это за преступник.
  2. Если вы получаете странные результаты, где иногда это работает, а иногда и нет, проверьте управление памятью. Для меня иногда это будет делать первое чтение, а иногда и нет. Это заставило меня поверить, что поток прекращается.
  3. Если я нахожу лучший способ сделать это, я вернусь и обновлю этот ответ.
  4. Управление памятью. Позвольте мне повторить: управление памятью.