Длина пакета iOS - PullRequest
       41

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

0 голосов
/ 12 марта 2012

Я пишу маленькое приложение, которое по сути меняет 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 ]

2 голосов
/ 13 марта 2012

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

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

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

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

1 голос
/ 15 марта 2012

Решение состояло в том, что когда не указано, 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]], чтобы очистить его.

0 голосов
/ 13 марта 2012

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

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

...