Отправка входящих сетевых сообщений в определенные потоки на основе идентификаторов сообщений в iOS (Swift 2)

Я копаюсь в кодировании iOS с помощью Swift, поэтому я новичок.

Мое приложение iOS (фактически игра) взаимодействует с игровым сервером, используя соединение с одним сокетом и собственный протокол JSON. Сообщения бывают односторонними (уведомления) и запрос/ответ (могут быть инициированы с обеих сторон). Запросы и ответы связаны друг с другом с помощью глобальных уникальных идентификаторов сообщений. Таким образом, это сильно отличается от простых запросов HTTP/REST.

Что может произойти сейчас (на самом деле проблема, которую мне нужно решить), например:

  • Сервер отправляет запрос (запрашивая определенное действие... например, ход игроков) (идентификатор сообщения S01)
  • Приложение одновременно отправляет запрос (для какого-то другого действия... например, список друзей) (идентификатор сообщения C01)

На данный момент моя игра для iOS использует класс SocketConnection, который подключается к серверу и может отправлять и получать (JSON) уведомления/запросы/ответы. Однако часть для отправки ответа потоку, инициировавшему запрос, отсутствует.

Я просмотрел документацию по iOS и множество блогов/учебников. Все они, кажется, охватывают GCD и то, как его использовать для параллелизма (перегрузка работы в рабочих и т. д.).

Однако мне нужно какое-то ожидание/уведомление, как в Java. Игровой сервер реализован на Java и при инициировании запроса клиента делает примерно следующее:

  • принять запрос и создать для него уникальный идентификатор сообщения
  • сохранить его в коллекции для дальнейшего использования
  • ожидание (тайм-аут) объекта запроса

В фоновом режиме есть выделенный (частный) поток получателя, который получает все входящие сообщения:

в то время как (! завершено) {

  • ждите следующего сообщения
  • если сообщение является ответом, найдите соответствующий запрос по идентификатору сообщения
  • поместите ответ в запрос
  • notify() инициатор запроса на объект запроса

}

Я думал о разделении соединений на 3 или более, чтобы чередующиеся сообщения запроса/ответа вообще не появлялись, но я думаю, что эта идея не очень хороша из-за: а) обработки нескольких соединений будет намного сложнее поддерживать стабильность игры и б ) в долгосрочной перспективе должна быть возможность параллельно играть в несколько игровых сессий внутри одного и того же экземпляра приложения iOS.

На данный момент я думаю, что семафоры и sleep() могли бы работать, что было бы похоже на шаблон, реализованный на сервере. Но прежде чем пытаться реализовать это, я хотел бы знать, возможно ли это. Семафоры кажутся довольно быстрыми, но мне понадобятся миллионы семафоров — по одному для каждого уникального идентификатора сообщения). А если использовать семафоры: как мне реализовать ожидание()? Использование цикла занятости с засыпанием и опросом семафора? Я думаю, что функция ожидания () просто использовала бы ожидание () на семафоре.

Заранее спасибо за любые отзывы или идеи.


person Alex    schedule 18.07.2015    source источник
comment
Зачем беспокоиться о специальном проводном протоколе? Просто используйте HTTP + удаленные уведомления или веб-сокеты и покончите с этим, чтобы вы могли сосредоточить больше усилий на важных и интересных аспектах создания игры.   -  person mattt    schedule 18.07.2015
comment
Я бы хотел больше сосредоточиться на самой игре :) Однако для веб-сокетов также потребуется собственный протокол (почти то, что я уже использую), плюс они/более тяжелые на стороне сервера (по крайней мере, spring веб-сокеты требуют контейнера J2EE), чем то, что у меня есть прямо сейчас. Кроме того, HTTP + REST плюс какой-то обратный канал для уведомлений означает 2 разных стека сообщений, которые, как мне кажется, кричат ​​о проблемах. О каких удаленных уведомлениях вы думали?   -  person Alex    schedule 19.07.2015


Ответы (1)


Однако мне нужно какое-то ожидание/уведомление, как в Java.

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

Как правило, в iOS это обрабатывается путем включения обработчика завершения или делегата вместе с запросом. Таким образом, ваш запрос будет выглядеть примерно так:

conn.sendRequest(request, completion: {
   // thing to do when it completes
})

Это не блокирует. sendRequest поместит completion в словарь идентификаторов запросов -> обработчики завершения. Когда ответ возвращается, вы ищете обработчик завершения и выполняете его. Например:

if let handler = self.handlers[identifier] {
    handler(response)
} else {
    // We got a response we weren't expecting... This may be an error, or we might ignore.
}

Дополнительные сведения о том, почему модель async/await очень плохо работает в iOS, см. в разделе Создание Адаптивные и эффективные приложения с GCD. См. также Руководство по параллельному программированию, и особенно раздел «Миграция из потоков».

person Rob Napier    schedule 18.07.2015
comment
Я собираюсь перенастроить клетки своего мозга и получить хорошее представление о GCD и очередях :) Приятно осознавать, что идея с семафорами, вероятно, рано или поздно потерпит неудачу. Одна вещь, которая может быть одновременно хорошей и плохой, может заключаться в том, что для использования очередей вызывающая сторона должна определить контекст вызова, чтобы позже он знал, в каком состоянии было приложение во время отправки первоначального запроса. Я предполагаю, что контекст вызова лучше всего передавать внутри блока (блок - это то, что помещается в очередь, верно?) для справки... - person Alex; 19.07.2015
comment
@ Алекс правильно. Блок может хранить состояние (он фиксирует переменные в области видимости, в которой он был создан), поэтому сам блок имеет весь контекст вызова, который вам нужен во многих случаях. Вы также можете создавать шаблоны производитель/потребитель, используя последовательные очереди, которые могут воссоздать многое из того, к чему вы привыкли. Очереди довольно дешевы (в отличие от потоков), поэтому не бойтесь создавать очереди для организации своей работы. - person Rob Napier; 19.07.2015