image

Предыстория


Мотивом написания данного приложения послужила курсовая работа по дисциплине «Компьютерные системы и сети». Честно говоря, эта одна из самых мной нелюбимых сторон в компьютерных технологиях, и я решил «подстраивать» курсовой проект под свои интересы, а именно, под Андроид-разработку.

Было решено создать библиотеку для соединения Андроид-устройств по средством Wi-Fi Direct технологии и передачи данных между ними (Wi-Fi Peer-to-Peer соединение осуществляется как раз с помощью технологии Wi-Fi Direct).

Почему Wi-Fi Direct?


После одобрения идеи о локальном соединении устройств передо мной встал вопрос: С помощью какой технологии собираюсь я это осуществить? Рассматривались следующие варианты:

  • Bluetooth
  • Wi-Fi Hotspot
  • Wi-Fi Direct или Wi-Fi Peer-to-Peer

Bluetooth


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

Wi-Fi Hotspot


Создание точки доступа является не плохим вариантом, однако меня смущает ситуация с потерей основного Wi-Fi соединения. Я бы хотел, чтобы пользователи могли находится в локальной сети, и одновременно иметь доступ к глобальной, например быть подключенными к своему домашнему роутеру.

Однако с помощью Wi-Fi Hotspot можно добиться максимальной скорости передачи данных (приложения Portal, SHAREit).

Wi-Fi Direct или Wi-Fi Peer-to-Peer


Данный подход решает все вышеупомянутые проблемы:

  1. неограниченное кол-во клиентов (если не так, прошу меня поправить)
  2. большой радиус действия
  3. соединение с устройствами по средством Wi-Fi без создания точки доступа
  4. технология поддерживается с API 14 (Android 4.0)

Но сразу закрадывается сомнение, мол Wi-Fi Peer-to-Peer, тогда как мы собираемся создать группу с владельцем и клентами, и тем более, чтобы все друг с другом общались. Это как раз-таки и является основной причиной написания данной статьи.

Wi-Fi Aware


Этот вариант не упоминал в основном списке, т.к. не считаю, что он может полноценно подойти для выполнения поставленной задачи. Однако Wi-Fi Aware является сравнительно молодой технологией для рассылки сообщений в определенном радиусе действия.

Начнем с проблем


Скажу честно, предоставляемая документация by developer.android.com давалась мне нелегко. И я начал искать сэмплы. Перебрав кучу материала, наткнулся на наиболее интересный sample by Google.

Никогда не думал, что на официальном сайте от Google можно найти говнокод, но это как раз тот случай. Однако даже этому стоит отдать должное, так как благодаря данному ресурсу я реализовал то, что хотел.

В сэмпле продемонстрирован пример чата двух устройств, которые нашли друг друга в списке, отображающем рядом находящиеся Wi-Fi Direct устройства с запущенным приложением чата. При выборе партнера непосредственно открывается ChatActivity.

Очень важным моментом является поиск собеседников: в списке не будут отображаться такие Wi-Fi Direct устройства, как телевизор или какая-нибудь гарнитура. Отображаются только устройства с запущенным Chat-приложением.

Также присутствовала проблема с тестированием. Тестировать работоспособность приложения необходимо было исключительно на реальных устройствах.

Что было реализовано для демонстрации работоспособности библиотеки


Приложение представляет следующий функционал:

  1. выбор роли в процессе работы с приложением (для примера были созданы «Мафия» и «Мирный житель»)
  2. создание группы
  3. присоединение к существующей группе
  4. общение между устройствами (при нажатии на кнопку меняется ее цвет как у инициатора, так и у всех остальных, соответствующих текущей роли (либо broadcast))

image

Описание экранов слева-направо:

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

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

image

Основная концепция работы библиотеки


Логика построена на основе архитектуры клиент-сервер. Сервером является владелец группы, клиентами — подсоединившиеся пользователи.

В приложении присутствуют собственные Serializer/Deserializer для преобразования передаваемых данных в массив байтов и обратно. В передаваемых данных хранится следующая информация:

  • кому отправить (мафии, мирным жителям, всем)
  • какого рода данные (например: изменение цвета кнопки)
  • сами данные (сериализованный Object)

Первый пункт «кому отправить» не совсем корректен, т.к. отправляются данные всем. Сначала серверу, потом сервер отправляет этот пакет всем клиентам. А вот клиент уже сам решает, стоит ему обрабатывать эти данные или нет. Сделано это по той простой причине, что сервер не знает ролей его клиентов. Таким образом было достигнуто равноправие в группе. Владелец отличается от всех остальных только тем, что его обременили заниматься передачей данных всем его клиентам.

Компоненты библиотеки


image

  • WifiDirectManager — основной класс библиотеки; отвечает за создание группы, поиск устройств, присоединение устройства в группу или приглашение в нее, отправка пакета данных всем участникам группы
  • WifiP2pDeviceObservable — реализация паттерна Observable; при нахождении Wi-Fi Direct устройства оповещает наблюдателя
  • WifiDirectBroadcastReceiver занимается оповещением приложения об изменениях Wi-Fi Direct соединения (например: удачно ли прошло соединение с другим устройством), состояния Wi-Fi на устройстве (например отключение должно последовать за собой предупреждение пользователя о невозможном продолжении работы приложения)
  • MessageShaper отвечает за сериализацию/десериализацию передаваемых данных; при десериализации на выходе получаем объект типа android.os.Message (obj — объект, what — для каких целей объект (например: поменять цвет кнопки), arg1 — тип доступа (для мафии, мирных жителей, либо broadcast))
  • Serializer непосредственно занимается сериализацией/десериализацией объектов
  • Status — характеризует каждое устройство как владельца группы, либо клиента
  • ChatNeedle хранит в себе сокет, по которому связаны два устройства между собой; обрабатывает input/output стримы данных; у клиента есть лишь один ChatNeedle — с владельцем, у владельца же их кол-во равняется кол-ву клиентов
  • Member — класс, описывающий участника группы (не себя самого), для дальнейшего использования в игровом сценарии; хранит в себе ChatNeedle для соединения с этим участником группы
  • MemberList — класс, хранящий в себе все устройства, с которыми связан наш девайс; в случае с владельцем группы — все клиенты, в случае клиента — владелец
  • GroupOwnerSocketHandler применяется владельцем группы для открытия определенного кол-ва сокетов, к которым подсоединяются клиенты
  • ClientSocketHandler используется для установления соединения клиента с владельцем группы

Самая сложная проблема во время разработки


Когда проект дошел до стадии тестирования мультиплеера (> 2 устройств), тут-то и началась жара. Два устройства как и прежде у меня соединялись без проблем (для чего впрочем и создан Wi-Fi Peer-to-Peer), однако при подсоединении третьего звена почти всегда происходил треш. При нажатии на кнопку у «владельца» (позже поймете, почему в кавычках) цвет менялся только у того клиента, с которым «владелец» последний раз общался.

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

До этого я считал, что тот девайс, который подсоединяется к другому, всегда будет клиентом… а это далеко не так. При соединении устройств рандомно передавались права владельца одному из них, что и побудило меня на поиск настройки config'a, который бы исправил эту ситуацию, и сделал подсоединяемое устройство клиентом.

При соединении двух устройств прописывается специальный config, который в себе содержит:

  • адрес устройства, к которому мы хотим присоединиться
  • wps.setup позволяет установить, как мы будем соединяться: с паролем или просто по нажатию кнопки
  • groupOwnerIntent — вот он (споймал!), тот, кто решил мою проблему; целочисленное поле, значение которого варьируется от 0 до 15 (0 — хотим быть клиентом, 15 — хотим быть владельцем); по умолчанию -1, что дает системе право самой выбрать роль в этой связи

        final WifiP2pConfig config = new WifiP2pConfig();
        config.deviceAddress = deviceAddress;
        config.wps.setup = WpsInfo.PBC;
        config.groupOwnerIntent = status.getIntent();
        mWifiP2pManager.connect(mWifiP2pManagerChannel, config, null);

Status'ом (enum) выше является текущее положение устройства, если он создатель группы — GroupOwner, иначе — Client.

Необходимые доработки


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

Защита. Для входа в определенную группу было бы неплохо реализовать авторизацию.

Заключение


Не думаю, что я реализовал что-то новое или революционное, однако данный проект послужил хорошим примером неординарного использования Wi-Fi Peer-to-Peer соединения. Мною была успешно построена сеть между устройствами с помощью Wi-Fi Direct, что позволило беспрепятственно общаться между ними.

Это моя первая статья, поэтому судить строго. Спасибо за внимание.

> Ссылка на GitHub
(модуль wifidirect может быть без проблем перенесен в любой андроид-проект)
Поделиться с друзьями
-->

Комментарии (20)


  1. bronico
    15.07.2017 14:51

    Для Android-разработчика понимание работы с сетью неотъемлемо. Успехов.


  1. a15199732
    15.07.2017 16:59
    +3

    «Invitation to connect» убивает всю прелесть приложений на основе Wi-Fi P2P. Найдёте способ подключаться без этого сообщения — Вам памятник поставят :)


    1. chelsenok
      15.07.2017 16:59

      да, отличное предложение


    1. blandger
      16.07.2017 10:58

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


      1. a15199732
        16.07.2017 17:07

        Странно решать вопрос доверия за разработчиков. Что мешает вытащить механизм авторизации в SDK?


        1. blandger
          16.07.2017 19:00

          Думаю, не доверие производителя платформы (Андроид и тд) к разработчику. А системных подходов в данном случае похоже пока нет, вот и зажимают возможности для разработки.


          1. izeberq
            20.07.2017 22:59

            А нельзя ли решить проблему через nearby пакет из play services?


            1. chelsenok
              20.07.2017 23:21

              Возможно, но это PlayServices


            1. stoplinux
              21.07.2017 07:13

              На сколько я помню при nearby обязательно подключение к одной WiFi сети


    1. chelsenok
      16.07.2017 15:40

      Может вы слышали что-нибудь об Xposed Framework? На стэке ходят ответы, которые указывают, мол именно этот инструмент может решить эту проблему…


      1. a15199732
        16.07.2017 16:59

        Если не смущает необходимость рута и установки дополнительного софта из левых источников (это всё для каждого из устройств, которые будут использовать Вашу библиотеку) — то да, видимо может.
        Но с рутом и никаких фреймворков не надо, можно вообще свой андроид с блэкджеком и шлюхами залить :)


  1. Areso
    15.07.2017 19:51

    Будет ли работать такая сеть, если: устройство 1 видит устройство 2, но не видит устройство 3; в свою очередь, устройство 3 видит устройство 2, но не видит устройство 1 в радиусе действия?


    1. chelsenok
      16.07.2017 11:02

      Да, если владельцем группы станет устройство 2
      В иных случаях получатся связи между двумя девайсамм


  1. gmikhail94
    15.07.2017 21:01

    Хорошая статья. Я когда-то тоже пытался сделать приложение-чат которое бы автоматически искало и соединялось с ближайшими устройствами по Wi-Fi (с установленным приложением) и выступало одновременно в роли клиента и ретранслятора. В идеале я хотел создать автоматически расширяемую децентрализованную Wi-Fi сеть без обязательной регистрации/идентификации.

    К моему большому удивлению, несмотря на то что идея не новая и даже есть несколько приложений которые заявляют подобный функционал, ни одно из них его не выполняло (!) и мало того — нагло обманывало пользователей. Зачастую все сводилось к двум типам:

    • Первый тип приложений требовал создание точки доступа (сервера), а клиенты к нему подключались. Соответственно все данные ходили через сервер, ни о какой масштабируемости сети не было и речи.
    • Второй тип приложений был обманкой. Клиенты подключались к удаленному серверу (через интернет), по GPS определялись координаты клиентов и на основе их координат выводился список «ближайших людей». Естественно все сообщения тоже передавались через интернет.

    Тогда я начал копать в сторону API, но там тоже возникли проблемы. Сначала решил действовать «грубой силой», передавать по Wi-Fi данные «в никуда», без предварительного сопряжения и идентификации устройств. Но, к сожалению, стандартными средствами Android API это невозможно. Wi-Fi Direct — не понял как реализовать автоматический поиск и автоматическое (без подтверждения) подключение множества устройств друг к другу. Wi-Fi Aware — тупо не смог найти ни какой документации или хотя бы подробного описания технологии.

    Буду рад если кто-то подскажет рабочие аналоги подобных приложений или выскажет свои идеи по реализации.


    1. chelsenok
      16.07.2017 11:04
      +1

      Отличный отзыв, при нахождении аналогов также натыкался на Вами указанные два пункта


    1. chelsenok
      16.07.2017 11:48
      +1

      Рассматривал все Вами упомянутые способы по беспроводной передаче данных, и пришел к выводу использовать Wi-Fi Direct. Однако, смотря на мои велосипеды и костыли, можно сказать точно — андроиду есть к чему стремиться в этом плане.


    1. stoplinux
      21.07.2017 07:12

      В свое время написал приложение Wi-Fi Direct рация (https://play.google.com/store/apps/details?id=ee.bl.artemka.wifiwalkingtalking) Включает в себя простенький обмен сообщениями. Но поддержку давно забросил к сожалению.


  1. olis
    18.07.2017 17:06
    +1

    Наверное, уместно напомнить, что существует The Serval Project, цель которого также обеспечить связь с без наличия соответствующей инфраструктуры.


    1. AndreyNagih
      18.07.2017 19:42
      +1

      А также протокол cjdns и сеть Hyperboria. И сеть Netsukuku.
      И обзорную статью по mesh-сетям.

      Тема очень интересная. Спасибо автору, что внес свой вклад.


      1. blandger
        22.07.2017 16:20

        Спасибо, надо посмотреть.
        А вот еще Challenge на 2$ миллиона, на похожую тематику «децентрализованного веб-а», правда с немного другой конценцией, рассматриваются железо + софт. Но боюсь, что приз маловат для этого.

        https://blog.mozilla.org/blog/2017/06/21/2-million-prize-decentralize-web-apply-today/
        Mozilla and the National Science Foundation are offering a $2 million prize for big ideas that decentralize the web. And we’re accepting applications starting today…