Длина пакета iOS

Я пишу небольшое приложение, которое по сути меняет местами XML туда-сюда в стиле SOAP. У меня есть сервер на базе OS X и клиент для iPad. я использую KissXML на клиенте и встроенный парсер XML на сервере. я использую GCDAsyncSocket на обоих общаться.

Когда я тестирую свое приложение на симуляторе iPad, получается полный XML. Все отлично работает

Тем не менее, когда я использую свое устройство разработки (настоящий физический iPad), все остальное работает нормально, но XML заканчивается после 1426-го символа. Я проверил, что эта ошибка происходит на нескольких iPad.

Когда я подписываюсь на входящие пакеты на GCDAsyncSocket я использую [sock readDataWithTimeout:-1 buffer:[NSMutableData new] bufferOffset:0 maxLength:0 tag:0]; а ранее просто простое [sock readDataWithTimeout:-1 tag:0]; но оба имеют одинаковый результат. Кажется, что GCDAsyncSocket не виноват во всяком случае, так как выполнение на симуляторе в порядке. Обратите внимание, что 0 в maxLength указывает на "бесконечный" буфер.

Кто-нибудь знает, что может быть причиной этого?

3 ответа

1426 звучит очень похоже на MTU (Maximum Transmit Unit), который является максимальным размером данных TCP, которые вы можете отправить. Это разные размеры на разных сетевых носителях и разных конфигурациях, но 1426 довольно распространено.

Это говорит о том, что вы путаете прием TCP-пакета с завершением XML-сообщения. Нет гарантии, что TCP-пакеты будут заканчиваться на границе сообщения XML. GCDAsyncSocket - это низкоуровневая библиотека, которая поддерживает протокол TCP, а не XML.

Когда вы получаете каждый пакет, вы обязаны объединить его в NSMutableData а затем решить, когда у вас будет достаточно, чтобы обработать его. Если ваш протокол закрывает соединение после каждого сообщения, вы можете читать, пока соединение не будет закрыто. Если нет, то вам придется иметь дело с тем фактом, что данный пакет может даже включать часть следующего сообщения. Вам придется анализировать данные в достаточной степени, чтобы решить, где находятся границы.

Кстати, вполне возможно, что ваш Mac имеет другой MTU, чем ваш iPad, поэтому вы можете наблюдать различное поведение на разных платформах.

Решение состояло в том, что когда не указано, AsyncSocket смотрит на следующую строку-возврат. Когда пакет завершается, он действительно возвращает строку. Я использовала (sock мой объект GCDAsyncSocket)

[sock readDatawithTimeout:-1 tag:0]

но с тех пор переехал в

[sock readDataToData:[msgTerm dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0]

где msgTerm является внешней константой NSString, определенной как "\r\n\r\n", и является общей для клиентского и серверного источника. Это эффективно обходит проблему возврата строки, заканчивающую пакет.

Еще одно примечание, касающееся этого решения: поскольку я использую протокол, подобный SOAP, пробелы не являются проблемой. Однако, если у вас есть темперамент по поводу завершения пробельных строк, вы можете использовать такой метод, как [incomingDecodedNsstringMessage stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] убрать это.

Посмотрев на код для GCDAsyncSocketЯ бы сказал, что вполне возможно, что в этом есть ошибка. Например, если вы читаете защищенный сокет, на iPhone используется механизм cfsocket вместо обычных файловых дескрипторов в стиле Unix, и автор может делать неверные предположения о том, когда сокет закрыт. Поскольку у вас есть исходный код, я бы попробовал пройтись по нему с помощью отладчика, чтобы посмотреть, не был ли конец файла помечен преждевременно.

TCP - это потоковый протокол. Теоретически размер пакета базового IP-протокола не должен иметь значения, но если вы будете читать сокет достаточно быстро, вы вполне можете получить данные в виде кусков размера IP-пакета, особенно если стек IP-адресов каким-то образом настроен для использования памяти (угадай здесь!).

Другие вопросы по тегам