iPhone: отправка больших данных с помощью Game Kit - PullRequest
5 голосов
/ 31 июля 2009

Я пытаюсь написать приложение, которое обменивается данными с другими iPhone-ами, и запускает приложение через каркас Game Kit. Айфоны обнаруживают друг друга и нормально подключаются, но проблемы возникают, когда я отправляю данные. Я знаю, что айфоны подключены правильно, потому что, когда я сериализую NSString и отправляю его через соединение, он выходит на другом конце в порядке. Но когда я пытаюсь заархивировать более крупный объект (используя NSKeyedArchiver), я получаю сообщение об ошибке «Ошибка AGPSessionBroadcast (801c0001)».

Я предполагаю, что это потому, что данные, которые я отправляю, слишком велики (размер моих файлов составляет около 500 КБ, кажется, Apple рекомендует максимум 95 КБ) Я попытался разделить данные на несколько передач, но я никогда не смогу их правильно разархивировать на другом конце. Мне интересно, сталкивался ли кто-нибудь еще с этой проблемой и как вы ее решили.

Ответы [ 2 ]

4 голосов
/ 22 августа 2009

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

Я закончил с простым государственным двигателем, который работал с обеих сторон. Отправитель передает заголовок с количеством отправленных байтов и размером пакета, затем ожидает подтверждения от другой стороны. Как только он получает рукопожатие, он переходит к отправке пакетов фиксированного размера, каждый из которых имеет порядковый номер.

Получатель получает каждый, читает его и добавляет его в буфер, а затем записывает обратно в канал, что он получил пакет с последовательностью #. Отправитель читает пакет #, вырезает значение другого буфера и так далее, и так далее. Каждая сторона отслеживает состояние, в котором она находится (в режиме ожидания, отправляющий заголовок, принимающий заголовок, отправка данных, получение данных, ошибка, выполнено и т. Д.) Обе стороны должны отслеживать, когда читать / записывать последний фрагмент, поскольку вероятно, будет меньше, чем полный размер буфера.

Это работает нормально (хотя и немного медленно) и может масштабироваться до любого размера. Я начал с размера пакетов 5K, но он работал довольно медленно. Повысил его до 10K, но он начал вызывать проблемы, поэтому я отступил и удержал его на уровне 8096. Он отлично работает как для двоичных, так и для текстовых данных.

3 голосов
/ 22 августа 2009

Имейте в виду, что GameKit не является общим API для передачи файлов; он больше предназначен для обновления информации о том, где находится игрок, о текущем местоположении или других объектах и ​​т. д. Поэтому отправка 300К для игры не кажется разумной, хотя я могу понять, как использовать API для общих механизмов обмена.

Проблема в том, что это не TCP-соединение; это больше UDP (датаграмма) соединение. В этих случаях данные представляют собой не поток (который упаковывается по протоколу TCP), а гигантский кусок данных. (Технически UDP можно фрагментировать на несколько IP-пакетов, но потерять один из них, и весь UDP будет потерян, в отличие от TCP, который будет повторяться).

MTU для большинства проводных сетей составляет ~ 1.5k; для блютуса это около ~ 0.5к. Таким образом, любой отправленный вами пакет UDP (а) может быть потерян, (b) может быть разбит на несколько IP-пакетов размером с MTU, и (c) если один из этих пакетов будет потерян, вы автоматически потеряете весь набор.

Ваша лучшая стратегия - эмулировать TCP - он отправляет пакеты с порядковым номером. Затем принимающая сторона может запросить двусторонние передачи пакетов, которые впоследствии пропали без вести. Если вы используете эквивалент NSKeyedArchiver, то одно из предложений - перебирать ключи и записывать их как отдельные ключи (при условии, что каждое значение ключа не так уж велико). Вам понадобится какой-то ACK для каждого отправляемого пакета и общий ACK, когда вы закончите, чтобы отправитель знал, что можно удалить данные из памяти.

...