- Использование сокетов в Android
- Особенности использования сокетов
- Клиентский android-сокет
- Класс Connection
- Листинг Connection
- Класс активности MainActivity
- Листинг активности
- Методы управления сокетным соединением
- Серверное приложение
- Листинг ConnectionWorker
- Серверный класс
- Листинг CallableDelay
- Листинг CallableServer
- Листинг серверного класса Server
- Использовать HTTP или Socket с Android
- Используйте HTTP или Socket с Android
- 4 ответа
- Простой клиент-сервер на Android (интернет-мессенджер)
- Делаем сервер
- Клиентская часть
Использование сокетов в Android
Создано большое количество приложений как для Android, так и для других ОС, которые взаимодействуют друг с другом с помощью установления соединенией по сети. К таким приложениям относятся, например, мессенджеры социальных сетей WhatsApp, Viber. Как правило, для установления соединения между такими приложениями используются сокеты.
Сокет (socket) — это интерфейс, позволяющий связывать между собой программы различных устройств, находящихся в одной сети. Сокеты бывают двух типов: клиентский (Socket) и серверный (ServerSocket). Главное различие между ними связано с тем, что сервер «открывает» определенный порт на устройстве, «слушает» его и обрабатывает поступающие запросы, а клиент должен подключиться к этому серверу, зная его IP-адрес и порт. В Android сокеты для передачи данных используют по умолчанию протокол TCP/IP, важной особенностью которого является гарантированная доставка пакетов с данными от одного устройства до другого.
Особенности использования сокетов
Что важно знать при использовании сокетов в Android ?
- соединения сокетов отключаются при переходе устройства в спящий режим;
- чтобы не «рвать» соединение при наступлении спящего режима в устройстве можно использовать сервис;
- для использования интернет-сети необходимо Android-приложению предоставить нужные права в манифесте.
Для определения прав в манифесте необходимо в файл AndroidManifest.xml добавить следующую строку :
Теперь android-приложения будет иметь доступ к сети.
Далее в статье рассмотрим пример клиент-серверного сокетного соединения с передачей сообщения. Функции клиента будет выполнять android-приложение. Серверное java-приложение выполним в IDE Eclipse с использованием пакета concurrent. В конце страницы можно скачать оба приложения.
Клиентский android-сокет
Интерфейс andriod-приложения представлен на следующем скриншоте. Форма приложения включает поле ввода текстового сообщения и кнопки установления соединения сервером, передачи сообщения и закрытия соединения.
Клиентское приложение создадим из двух классов : класс взаимодействия с серверным сокетом Connection и класс стандартной активности MainActivity.
Класс Connection
Класс взаимодействия с сервером Connection получает при создании (через конструктор) параметры подключения : host и port. Методы Connection вызываются из активности и выполняют следующие функции :
Метод | Описание |
---|---|
openConnection | Метод открытия сокета/соединения. Если сокет открыт, то он сначала закрывается. |
closeConnection | Метод закрытия сокета |
sendData | Метод отправки сообщения из активности. |
finalize | Метод освобождения ресурсов |
Листинг Connection
Класс активности MainActivity
В активности MainActivity определены параметры сервера : host, port. Помните, что IP-адрес сервера для Вашего android-примера не может быть localhost (127.0.0.1), иначе Вы будете пытаться связаться с сервером внутри Andriod-системы. Кнопки интерфейса связаны с методами обращения к классу Connection. Кнопки отправки сообщения mBtnSend и закрытия соединения mBtnClose с сервером блокируются при старте приложения. После установления соединения с сервером доступ к кнопкам открывается.
Листинг активности
Методы управления сокетным соединением
Ниже представлены методы обработки событий, связанных с нажатием кнопок интерфейса. Обратите внимание, что подключение к серверу выполняется в отдельном потоке, а открытие доступа к кнопкам в основном потоке, для чего вызывается метод runOnUiThread. Для отправки сообщения серверу также создается отдельный поток.
Серверное приложение
Серверное приложение включает 2 класса : Server и ConnectionWorker. Серверный класс Server будет выполнять обработку взаимодействия с клиентом с использованием ConnectionWorker в отдельном потоке. Конструктор ConnectionWorker в качестве параметра получает объект типа Socket для чтения сообщений клиента из потока сокета.
Листинг ConnectionWorker
ConnectionWorker получает входной поток inputStream из клиентского сокета и читает сообщение. Если сообщение отсутствует, т.е. количество прочитанных байт равно -1, то это значит, что соединение разорвано, то клиентский сокет закрывается. При закрытии клиентского соединения входной поток сокета также закрывается.
Серверный класс
Серверный класс Server создадим с использованием многопоточного пакета util.concurrent. На странице описания сетевого пакета java.net и серверного ServerSocket был приведен пример серверного модуля с использованием обычного потока Thread, при работе с которым необходимо решать задачу его остановки : cтарый метод Thread.stop объявлен Deprecated и предан строжайшей анафеме, а безопасная инструкция Thread.interrupt безопасна, к сожалению, потому, что ровным счетом ничего не делает (отправляет сообщение потоку : «Пожалуйста, остановись»). Услышит ли данный призыв поток остается под вопросом – все зависит от разаработчика.
Чтобы иметь возможность остановить сервер «снаружи» в серверный класс Server включим 2 внутренних реализующих интерфейс Callable класса : CallableDelay и CallableServer. Класс CallableDelay будет функционировать определенное время, по истечении которого завершит свою работу и остановит 2-ой серверный поток взаимодействия с клиентами. В данном примере CallableDelay используется только для демонстрации остановки потока, организуемого пакетом util.concurrent.
Листинг CallableDelay
CallableDelay организует цикл с задержками. После завершения последнего цикла cycle поток завершает цикл, останавливает вторую задачу futureTask[1] и закрывает сокет. В консоль выводится соответствующее сообщение.
Листинг CallableServer
Конструктор CallableServer в качестве параметров получает значение открываемого порта для подключения клиентов. При старте (метод call) создается серверный сокет ServerSocket и поток переходит в режим ожидания соединения с клиентом. Остановить поток можно вызовом метода stopTask, либо завершением «задачи» типа FutureTask с данным потоком.
При подключении клиента метод serverSoket.accept возвращает сокет, который используется для создания объекта ConnectionWorker и его запуска в отдельном потоке. А сервер (поток) переходит к ожиданию следующего подключения.
В случае закрытия сокета (завершение внешней задачи FutureTask с данным потоком) будет вызвано исключение Exception, где выполняется проверка закрытия сокета; при положительном ответе основной цикл прерывается и поток завершает свою работу.
Листинг серверного класса Server
Cерверный класс Server создает два потоковых объекта (callable1, callable2), формирует из них две задачи futureTask и запускает задачи на выполнение методом execute исполнителя executor. После этого контролируется завершение выполнение обоих задач методом isTasksDone. При завершении выполнения обеих задач завершается также и цикл работы executor’а.
Два внутренних описанных выше класса (CallableDelay, CallableServer) не включены в листинг.
Источник
Использовать HTTP или Socket с Android
Мне приходится отправлять данные с телефона Android на сервер очень часто, скажем, каждые 100 мс (батарея не проблема). Я обсуждаю с самим собой, нормально ли использовать стандартное соединение с URL-адресом Java для этой цели или создать собственную реализацию собственного сокета с использованием SocketChannel. Я имею полный контроль над обоими конечными точками и свободно выбираю все, что хочу. Каковы плюсы и минусы каждого из этих методов? Любой другой подход? Обратите внимание, что я уже пробовал Google XMPP. Но выяснилось, что многие точки данных падают. Не получил от Google ответа об этом.
Обратите внимание, что надежность является первоочередной задачей. Я должен получить каждый образец в реальном времени, если, конечно, не существует какой-либо проблемы в самой радиосвязи. Укажите несколько указателей.
Соединение Socket TCP:
- (+) Надежная доставка из-за повторной передачи пакетов TCP.
(-) Нестандартные порты/протокалы блокируются многими поставщиками мобильного Интернета.
(-) Повторная передача пакетов может вызвать задержки и, следовательно, не в реальном времени.
Подключение Socket UDP
- (+) Если пакет проходит через него, он получает самую низкую задержку этих методов.
(-) Нестандартные порты/протокалы блокируются многими поставщиками мобильного Интернета.
(-) Неверная доставка, пакеты могут быть дублированы, усечены или опущены.
- (+) Многие пользователи могут использовать ваше приложение (многие мобильные интернет-провайдеры блокируют порты рядом с HTTP (80) и HTTPS (443) и используют глубокую проверку пакетов (для HTTP), чтобы убедиться, что протокол соблюден).
Самый надежный из-за повторной передачи TCP и прокси.
(-) Повторная передача пакетов TCP может вызывать задержки и, следовательно, не в реальном времени.
(-) Прокси могут добавить дополнительные задержки, что приведет к еще меньшему времени реального времени.
Источник
Используйте HTTP или Socket с Android
Мне нужно отправлять данные с телефона Android на сервер, очень часто, каждые 100 мс (батарея не проблема). Я спорю сам с собой, можно ли использовать для этой цели стандартное URL-соединение Java или создать свою собственную реализацию сокета с помощью SocketChannel. Я полностью контролирую обе конечные точки и могу выбирать все, что захочу. Каковы плюсы и минусы каждого из этих методов? Любой другой подход? Обратите внимание, что я уже пробовал Google XMPP. Но обнаружил, что многие точки данных теряются. Не получил ответа от Google по этому поводу.
Обратите внимание, что надежность — это первоочередная задача. Я должен получать каждый образец в режиме реального времени, если, конечно, нет проблем с самой радиосвязью. Пожалуйста, дайте несколько указателей.
4 ответа
Я рассматривал различные варианты: http, xmpp, кастомную реализацию сокета . наконец я наткнулся на https://github.com/Gottox/socket.io-java-client . Сработало безболезненно. Я был готов к работе в кратчайшие сроки! Конечно, помогло то, что я использовал socket.io в более раннем проекте. Я никогда не думал, что для socket.io будет Java-клиент! Думаю, я задавал неправильные вопросы. Пока это решение работает очень хорошо. Я буду тестировать и размещать обновления, если таковые будут. Рассмотрите этот вариант, если вам нужно реализовать постоянную связь в реальном времени.
Соединение сокета TCP:
- (+) Надежная доставка за счет повторной передачи TCP-пакетов.
- (-) Нестандартные порты / протоколы блокируются многими провайдерами мобильного интернета
- (-) Повторная передача пакета может вызывать задержки и, следовательно, не в реальном времени.
Соединение сокета UDP
- (+) Если пакет приходит, он получен с наименьшей задержкой среди этих методов.
- (-) Нестандартные порты / протоколы блокируются многими провайдерами мобильного интернета
- (-) Доставка ненадежная, пакеты могут дублироваться, урезаться или отбрасываться.
- (+) Многие пользователи могут использовать ваше приложение (многие провайдеры мобильного Интернета блокируют порты, кроме HTTP (80) и HTTPS (443), и используют глубокую проверку пакетов (для HTTP), чтобы убедиться, что протокол соблюдается).
- Самый надежный из-за повторной передачи TCP и прокси.
- (-) Повторная передача TCP-пакетов может вызывать задержки и, следовательно, не в реальном времени.
- (-) Прокси-серверы могут добавлять дополнительные задержки, что делает его еще менее реальным.
Если вам приходится передавать данные довольно часто, имеет смысл использовать сокеты. Вы можете поддерживать соединение открытым в течение долгого времени, отправляя пакеты в одном и том же канале, и не тратить ресурсы на его повторное открытие при каждой передаче.
Источник
Простой клиент-сервер на Android (интернет-мессенджер)
Важно. Все написанное ниже не представляет собой какой либо ценности для профессионалов, но может служит полезным примером для начинающих Android разработчиков! В коде старался все действия комментировать и логировать.
Поехали. Многие мобильные приложения (и не только) используют архитектуру клиент-сервер. Общая схема, думаю, понятна.
Уделим внимание каждому элементу и отметим:
- сервер — представляет собой некую программу, работающую на удаленном компьютере, и реализующую функционал «общения» с приложениями-клиентами (слушает запросы, распознает переданные параметры и значения, корректно отвечает на них);
- клиент — в нашем случае, программа на мобильном устройстве, которая умеет формировать понятный серверу запрос и читать полученный ответ;
- интерфейс взаимодействия — некий формат и способ передачи/получения запросов/ответов обеими сторонами.
Неважно, как реализован любой из этих элементов, все они в любом случае присутствуют. Давайте реализуем примитивный сервер и Android клиент, работающий с ним. Как пример, будем использовать любой популярный мобильный интернет-мессенджер (Viber, ICQ), а приложение условно назовем «интернет-чат».
Схема взаимодействия следующая:
Клиент, установленный на устройстве А, посылает сообщение для клиента, установленного на устройстве Б. И наоборот. Сервер играет роль связующего звена между устройством А и Б… С, Д… и т.д. Также он играет роль «накопителя» сообщений, для их восстановления, на случай удаления на одном из клиентских устройств.
Для хранения сообщений используем SQL БД как на сервере, так и на устройствах-клиентах (в принципе, вся работа клиентов интернет-мессенджеров и сводится к постоянной синхронизации локальной и удаленной БД с сообщениями). Дополнительно, наш интернет-чат будет уметь стартовать вместе с запуском устройства и работать в фоне. Взаимодействие будет происходить путем HTTP запросов и JSON ответов.
Более логично, если синхронизация происходит через порт/сокет, это с одной стороны упрощает задачу (не нужно циклично слать HTTP запросы на проверку новых сообщений, достаточно проверять состояние прослушиваемого сокета), но с другой стороны, это усложняет создание серверной части приложения.
Делаем сервер
Для реализации «сервера», нам нужно зарегистрироваться на любом хостинге, который дает возможность работы с SQL и PHP.
Создаем пустую SQL БД, в ней создаем таблицу.
- author — автор сообщения;
- client — получатель сообщения;
- data — время и дата получения сообщения на сервере;
- text — сообщение.
В двух следующих файлах необходимо изменить переменные, содержащие данные для доступа к БД, на свои, полученные Вами при регистрации Вашего«сервера».
Структура запросов к api:
- обязательный атрибут action — может быть равен select (сервер ответит списком записей из своей БД), insert (сервер добавить новую запись в свою БД), delete (сервер очистит свою БД)
- если action=insert, нам нужно будет передать дополнительные параметры: author (кто написал сообщение), client (кому адресовано сообщение), text (сообщение)
- action=select может содержать дополнительный параметр data, в этом случае ответ сервера содержит не все сообщения из БД, а только те, у которых время создания позднее переданного
Примеры:
- chat.php?action=delete – удалит все записи на сервере
- chat.php?action=insert&author=Jon&client=Smith&text=Hello — добавит на сервере новую запись: автор Jon, получатель Smith, содержание Hello
- chat.php?action=select&data=151351333 — вернет все записи, полученные после переданного времени в long формате
Клиентская часть
Теперь структура Android приложения:
В фоне работает FoneService.java, который, в отдельном потоке, каждые 15 секунд делает запрос на сервер. Если ответ сервера содержит новые сообщения, FoneService.java записывает их в локальную БД и отправляет сообщение ChatActivity.java о необходимости обновить ListView, с сообщениями. ChatActivity.java (если она в этот момент открыта) получает сообщение и обновляет содержимое ListView из локальной БД.
Отправка нового сообщения из ChatActivity.java происходит сразу на сервер, минуя FoneService.java. При этом наше сообщение НЕ записывается в локальную БД! Там оно появится только после получения его назад в виде ответа сервера. Такую реализацию я использовал в связи с важным нюансом работы любого интернет-чата — обязательной группировкой сообщений по времени. Если не использовать группировку по времени, будет нарушена последовательность сообщений. Учитывая, что клиентские приложения просто физически не могут быть синхронизированы с точностью до миллисекунд, а возможно будут работать даже в разных часовых поясах, логичнее всего будет использовать время сервера. Так мы и делаем.
Создавая новое сообщение, мы передаем запросом на сервер: имя автора сообщения, имя получателя сообщения, текст сообщения. Получая эту запись назад, в виде ответа сервера, мы получаем то, что отправляли + четвертый параметр: время получения сообщения сервером.
Источник