Wi-Fi P2P. Информировать всех доступных пиров о некотором событии

Проблема: я делаю офлайн-многопользовательскую игру для Android, в которой люди могут создавать или присоединяться к комнате и играть вместе через Wi-Fi. Рассмотрим ситуацию, когда пользователь создает комнату и он (конечно) должен сообщить всем остальным пользователям, что комната свободна. Итак, вопрос: «Как?». Я прочитал около 1000 раз это и это. Там написано, что для отправки каких-то данных на другое устройство одно из них должно быть сервером, а другое клиентом. Клиент отправляет некоторую информацию на сервер, сервер ее принимает. Значит ли это, что я должен сделать всех "игроков" серверами, а "создатель комнаты" должен стать клиентом? Это звучит безумно. Пожалуйста, помогите, может быть, я читаю не те документы?


person Sergey Maslov    schedule 19.04.2015    source источник


Ответы (2)


Прежде всего, вам нужно помнить, что если вы решите использовать WiFiP2P в своем проекте, вам нужно будет подготовиться к трудным временам. К сожалению (как вы уже могли заметить :)) WiFiP2P официальная документация по Android не так хороша. Различные устройства ведут себя по-разному (например, они вызывают некоторые события WifiP2P в разном порядке), и документы вообще не охватывают это. Достижение стабильной связи требует введения нестандартных, а иногда и кардинальных мер. Получение WifiP2P соединения неразрывно связано с отображением системного окна (с вопросом, действительно ли вы хотите подключиться к устройству).

Перед тем, как приступить к реализации решения WifiP2P, необходимо рассмотреть несколько моментов:

  1. Смогут ли игроки вашей игры подключаться более чем к одной комнате одновременно?
  2. Смогут ли игроки вашей игры обнаружить новую комнату, когда они подключены к другой?
  3. Смогут ли игроки вашей игры называть свои комнаты «человекочитаемыми» именами? И эти имена будут использоваться другими пользователями (не создателем комнаты) для выбора комнаты, к которой они хотели бы подключиться?

Сценарий А:

Если вы ответили «Да» на вопрос 1 или 2, вам нужно серьезно подумать, действительно ли вы хотите использовать WifiP2P. WifiP2P (реализация Wifi-Direct для Android) не совсем соответствует вашим потребностям. Использование WifiP2P, вероятно, означает, что владелец комнаты создает WifiP2P-group, и любой человек, который хочет присоединиться к комнате, должен подключиться к этой WifiP2p-group. Проблема в том, что Android не позволяет одному устройству присоединяться к нескольким группам одновременно (что также означает, что он не позволяет создавать несколько групп одновременно). Обнаружение изменений в доступных WiFiP2P устройствах вокруг также проблематично (когда вы уже подключены к устройству).

Если вы действительно хотите использовать Wifi-Direct, вам, вероятно, потребуется использовать один WiFiP2P-group и подключить к нему все устройства. Эта группа будет действовать как обычная сеть, и всем, что связано с игровой комнатой, должен управлять один узел, выступающий в роли типичного сервера (или, может быть, не типичного сервера, а какого-то другого сетевого решения).

Если вам действительно не нужен WifiP2P, используйте обычный Wifi. Подключите все устройства к одной сети (возможно, даже создайте точку доступа на одном из ваших устройств), и весь процесс подключения может быть относительно простым, выполняемым в фоновом режиме без непосредственного участия пользователя. Удобочитаемые имена комнат не проблема, так как вы можете отправить что угодно со своего сервера.

Сценарий Б:

Если вы ответили «Да» на вопрос 3. и вам действительно нужно использовать WifiP2P, вам нужно будет найти способ транслировать ваши «удобочитаемые» имена на другие устройства.

Вы, наверное, думаете, что это очень просто: вы подключаетесь к другому устройству, говорите название созданной вами комнаты, и все готово. Не так просто. Как я сказал ранее:

получение WifiP2P соединения неразрывно связано с отображением системного окна (с вопросом, действительно ли вы хотите подключиться к устройству)

Таким образом, весь процесс будет более-менее:

  1. Устройство A: инициируйте подключение к устройству B (этот шаг также может быть выполнен устройством B)

  2. Устройство B: появляется уродливое системное окно с вопросом, хотите ли вы подключиться к Android-ao12ij219sa (какое-то ПРОГРАММНО НЕИЗМЕНИМОЕ имя системного устройства)

  3. Устройство Б: принимает

  4. Устройство B: ожидание результата подключения

  5. Устройство B: подключено, ожидание информации о названии комнаты устройства A

  6. Устройство А: подключено, отправляет название комнаты

  7. Устройство B: получено имя комнаты устройства A, отключение (будущий запрос на подключение также приведет к отображению системного окна)

Пока выполняются шаги 1-7, никакое другое устройство не может подключиться к устройству А (поэтому в это время никакое другое устройство не может получить имя комнаты).

Что можно сделать:

  1. Используйте WifiP2P Service Discovery. Это позволяет передавать некоторую информацию без необходимости установления соединения. К сожалению, он задокументирован еще хуже, чем сам WifiP2P, и может быть еще менее надежным (субъективно). Если вы хотите создать надежное решение, основанное на этом, вам придется потратить часы на тестирование и поиск различных случаев, в которых оно может не работать. Я знаю по опыту, что это возможно, но потребует от вас реализации ряда обходных путей, чтобы всегда можно было получить стабильное WiFiP2P соединение.

  2. Отправьте на свои устройства сопоставление между этими (неизменяемыми) WifiP2P именами и именами созданных комнат другим способом. Например, через API вашего сервера или что-то в этом роде...

person Bartek Lipinski    schedule 21.04.2015
comment
Большое спасибо за Ваш ответ! У меня остался только один вопрос: вы сказали, что обнаружение сервисов может быть менее надежным. Что это значит? Часто отключается? И что вызывает эту проблему? Аппаратное или программное обеспечение? Благодарю вас! - person Sergey Maslov; 22.04.2015
comment
Возможно, надежный — не лучшее слово. Я имел в виду следующее: использование Service Discovery приводит к еще большему количеству необычных случаев поведения устройства, которые вам нужно предвидеть, чтобы убедиться, что ваше приложение работает правильно. Чтобы ваши игровые комнаты всегда обнаруживались, чтобы ваши клиенты всегда могли подключиться к комнате, и так далее, и тому подобное… - person Bartek Lipinski; 22.04.2015
comment
@BartoszLipinski в своем ответе вы сказали, что с помощью WifiP2P Service Discovery я могу транслировать некоторую информацию без необходимости установления соединения, не могли бы вы объяснить мне, как я могу это сделать? Я имею в виду, если у меня есть служба на моем устройстве, как я могу транслировать, что что-то изменилось? Я был бы очень признателен, - person zer0uno; 13.10.2015
comment
@Bartek Lipinski вы можете использовать метод setDeviceName WiFiP2pManger, который помечен @hide через отражение. Я пытался использовать его для изменения имени устройства, и он отлично работает. Но все же процесс обнаружения идет с некоторыми странными проблемами. Например, устройство A продолжает получать намерение WIFI_P2P_PEERS_CHANGED_ACTION, которое содержит устройство B в списке узлов, даже если Wi-Fi на устройстве B отключен. - person Niakros; 21.03.2016
comment
@Niakros Я всегда стараюсь не использовать отражение. Это может стать действительно ненадежным, особенно если вы возитесь с некоторыми методами, которые разработчики (в данном случае разработчики Google) не хотели, чтобы вы использовали. Если метод не является частью общедоступного API, его можно менять от сборки к сборке. И никакой информации об этом не будет. - person Bartek Lipinski; 21.03.2016
comment
@Bartek Lipinski, я абсолютно согласен, но скажи мне, пожалуйста. Что вы делаете с постоянными группами прямого доступа к Wi-Fi на приглашенных устройствах? Каждый момент, когда хост-устройство создает новую группу и приглашает пиров, новая группа сохраняется на приглашенных устройствах после подключения устройства (что можно увидеть в Wi-Fi — прямая настройка в меню Wi-Fi Android). Вызов removeGroup на одноранговых устройствах не удаляет эту группу. Просто отключается от него. В настоящее время я использую метод @hide deletePersistentGroup для удаления групп после отключения. Разве я не должен это делать? - person Niakros; 21.03.2016
comment
@Niakros, я не думаю, что я что-то с ними делал. Я не думаю, что они были проблемой в моем случае. Извините, я не могу помочь вам с ответом. - person Bartek Lipinski; 21.03.2016
comment
@BartekLipinski извините за назойливость, но не могли бы вы помочь мне еще с одним вопросом? Я реализовал систему обнаружения/трансляции, как вы описали здесь: stackoverflow.com/a/31641302/3106249. И у меня есть проблема: когда хост-устройство приглашает одноранговое устройство, на одноранговом устройстве появляется системный диалог с просьбой принять соединение (статус однорангового узла становится ПРИГЛАШЕН и не изменяется до перезагрузки Wi-Fi), но он никогда не появляется на хосте. Есть ли у вас какие-либо мысли по этому вопросу? - person Niakros; 22.03.2016
comment
@Niakros, что вы имеете в виду под тем, что он никогда не появляется на хосте? - person Bartek Lipinski; 25.03.2016
comment
@BartekLipinski Я имею в виду, что после того, как я подтвержу подключение на приглашенном устройстве, на хост-устройстве вообще ничего не произойдет, и в моем приемнике не появится сообщение wifi_p2p, несмотря на то, что должно появиться то же диалоговое окно подтверждения подключения. Я жду до 60 секунд события WIFI_P2P_CONNECTION_CHANGED_ACTION, которое появляется после того, как обе стороны подтвердили соединение, может быть, мне следует подождать дольше? - person Niakros; 25.03.2016
comment
@BartekLipinski разве вы никогда раньше не видели WifiP2pService: результат приглашения INFORMATION_IS_CURRENTLY_UNAVAILABLE ? - это то, что я вижу в журналах, когда диалоговое окно принятия не появляется на хост-устройстве. - person Niakros; 30.03.2016
comment
@Niakros Проблема в том, что прошло довольно много времени с тех пор, как я в последний раз работал с WifiP2p (большинство моих сообщений о WifiP2P относятся к первой половине прошлого года), и, честно говоря, я просто не могу вспомнить все, с чем столкнулся. Это. Вы пытались сбросить Wi-Fi, прежде чем вообще возиться с WifiP2p? - person Bartek Lipinski; 30.03.2016
comment
@BartekLipinski да, я пытался. И тут проблема повторяется - person Niakros; 30.03.2016
comment
@Niakros Тогда я не думаю, что смогу сильно помочь. Продолжайте пробовать, приятель, и дайте мне знать, если вам удастся решить вашу проблему. Удачи! - person Bartek Lipinski; 30.03.2016

По сути, ваш дизайн, как я вижу, имеет очень простое решение для дизайна с Wifi Direct.

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

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

Затем с клиентами просто выполните обнаружение службы, и как только вы найдете «комнату», просто подключитесь к ней.

Затем, когда соединения инициируются клиентами, диалоговые окна принятия должны отображаться на стороне владельцев группы.

person Dr.Jukka    schedule 21.04.2015
comment
Большое спасибо! Не могли бы вы пояснить: сервер МОЖЕТ отправлять данные всем подключенным одноранговым узлам, верно? - person Sergey Maslov; 21.04.2015
comment
В основном ваш сервер на этот раз будет владельцем группы группы Wifi Direct. Все клиенты будут подключаться к владельцу группы, поэтому владелец группы сможет с ними общаться. - person Dr.Jukka; 21.04.2015
comment
Опять же, информация о группе содержит только IP-адрес владельца группы, поэтому самый простой способ начать общение — запустить его с клиента. - person Dr.Jukka; 21.04.2015