Реализация постоянного соединения с сервером в iPhone-приложении

Алексей Скрябин

Алексей Скрябин

IT-копирайтер

#Мобильная разработка

31 Окт 2012

Время чтения: 4 минуты

31 Окт 2012

Разработка программного обеспечения никогда не сможет стать рутинной работой, особенно если вы специализируетесь на столь динамичных технологиях как мобильные. Каждая задача имеет свои сложности и тонкости, изящная реализация которых и приводит к успеху. Например, во время работы над текущим проектом, встал вопрос о том, как реализовать обмен информацией с сервером. Проблема в общем-то достаточно распространенная, но требует четкого понимания особенностей контекста применения для выбора конкретной реализации.

Выбирали из двух вариантов: обмен информацией с помощью http-запросов и, собственно, реализация постоянного соединения.

Первый вариант обладал следующими преимуществами: простота реализации, а также использование в подавляющем большинстве проектов, где требуется работа с сетью.

С вариантом постоянного соединения все было сложнее, потому что опыта работы с ним было немного. Но этот способ обладал явными преимуществами по сравнению с http-запросами. Во-первых, скорость обмена информацией. Во-вторых, мгновенное получение сообщений, инициированных самим сервером, без необходимости постоянного опроса сервера. И наконец, отсутствие необходимости передавать каждый раз идентификатор соединения, тем самым сильно облегчая работу пользователей.

В результате, в соответствии со спецификой приложения, было решено использовать способ с постоянным соединением.

В связи с тем, что приложение должно передавать на сервер личную информацию (данные о платежных картах), необходимо было сделать защищенное соединение  с использование ssl протокола. Это тоже повлияло на некоторые детали реализации.

Ниже будут описаны ключевые моменты того, как это было сделано соединение с сервером на постоянной основе.

Инициализация соединения

В стандартной библиотеке компонентов iOS SDK есть классы для работы с потоками, на базе класса NSStream, но у него отсутствует возможность задать необходимые параметры ssl при соединении по сети, поэтому пришлось использовать более низкоуровневый класс на базе CFStream:

После этого CFStream можно привести к типу NSStream, для более удобной работы :

                    Листинг 2. Приведение типов

            Задание параметов ssl:

           Листинг 3. Задание необходимых параметров для работы по ssl соединению

Как раз ради того, чтобы задать параметры ssl соединения, необходимо было воспользоваться низкоуровневыми потоками CFStream.

Асинхронный обмен данными

Чтобы приложение работало в реальном времени, не вызывая блокировок пользовательского интерфейса, обмен данными с сервером необходимо осуществлять асинхронно. Т.е. если мы отправили запрос на сервер, то не обязательно ждать ответа, находясь в полном бездействии, в это время можно заниматься своими делами, а когда сервер пришлет ответ, мы его обработаем по мере получения, выполнив необходимые действия. Для этого необходимо задать потокам чтения и записи объект класса способного обрабатывать сообщения от сервера. В данном случае объект-обработчик является тем же объектом, в котором создается соединение:


       
    Листинг 4. Задание делегата на обработку событий потоков чтения и записи.

Класс, объект которого будет получать сообщения от NSStream объектов должен реализовывать протокол NSStreamDelegate. Чтобы иметь возможность обрабатывать сообщения от потоков, класс, объект которого будет получать сообщения от NSStream-объектов, должен реализовывать протокол  NSStreamDelegate. Функция обработки выглядит следующим образом:



              Листинг 5. Метод, отвечающий за обработку сообщений от сервера.

В данном методе обрабатываются несколько типов сообщений от сервера. Наиболее интересным является  NSStreamEventHasBytesAvailable, который сигнализирует нам о том, что у сервера есть данные, которые он хочет нам переслать. Также тут обрабатываются сообщения об ошибках, об успешном открытии соединения и о том, что поток готов к записи.

После всего этого, если отсутствуют ошибки, можно открывать потоки и работать с сервером:

           Листинг 6. Открытие созданных ранее потоков (с проверкой на наличие ошибок)

Сериализация данных

В качестве удобного способа сериализации/десериализации информации была использована библиотека protobuf от Google, реализация которой есть под многие платформы, в частности и под iOS. Данная библиотека уже не один раз применялась в проектах компании, поэтому сложности с ее использованием не возникло.

Проблемы в разработке

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

Из этого можно сделать вывод о том, что искать решения проблем необходимо комплексно, так как причина может оказаться в самом неожиданном месте.

Преимущества постоянного соединения:

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

Как следствие требуется менее мощное серверное и сетевое оборудование, чем при использовании http-запросов. Возможна более оперативная реакция клиентского приложения на события на сервере. Снижение общего времени на сетевые операции на клиенте.

Комментарии

Фильтр

Закрыть

Технологии

Индустрии