- Использование сокетов в Android
- Особенности использования сокетов
- Клиентский android-сокет
- Класс Connection
- Листинг Connection
- Класс активности MainActivity
- Листинг активности
- Методы управления сокетным соединением
- Серверное приложение
- Листинг ConnectionWorker
- Серверный класс
- Листинг CallableDelay
- Листинг CallableServer
- Листинг серверного класса Server
- Native Socket.IO and Android
- Introduction#
- Installing the Dependencies#
- Using socket in Activity and Fragment#
- Emitting events#
- Listening on events#
- Managing Socket State#
- Further reading#
- Управляем компьютером с 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) не включены в листинг.
Источник
Native Socket.IO and Android
In this tutorial well learn how to create a chat client that communicates with a Socket.IO Node.JS chat server, with our native Android Client! If you want to jump straight to the code, it’s on GitHub. Otherwise, read on!
Introduction#
To follow along, start by cloning the repository: socket.io-android-chat.
The app has the following features:
- Sending a message to all users joining to the room.
- Notifies when each user joins or leaves.
- Notifies when an user start typing a message.
Socket.IO provides an event-oriented API that works across all networks, devices and browsers. It’s incredibly robust (works even behind corporate proxies!) and highly performant, which is very suitable for multiplayer games or realtime communication.
Installing the Dependencies#
The first step is to install the Java Socket.IO client with Gradle.
For this app, we just add the dependency to build.gradle :
We must remember adding the internet permission to AndroidManifest.xml .
Now we can use Socket.IO on Android!
Using socket in Activity and Fragment#
First, we have to initialize a new instance of Socket.IO as follows:
IO.socket() returns a socket for http://chat.socket.io with the default options. Notice that the method caches the result, so you can always get a same Socket instance for an url from any Activity or Fragment. And we explicitly call connect() to establish the connection here (unlike the JavaScript client). In this app, we use onCreate lifecycle callback for that, but it actually depends on your application.
Emitting events#
Sending data looks as follows. In this case, we send a string but you can do JSON data too with the org.json package, and even binary data is supported as well!
Listening on events#
Like I mentioned earlier, Socket.IO is bidirectional, which means we can send events to the server, but also at any time during the communication the server can send events to us.
We then can make the socket listen an event on onCreate lifecycle callback.
With this we listen on the new message event to receive messages from other users.
This is what onNewMessage looks like. A listener is an instance of Emitter.Listener and must be implemented the call method. Youll notice that inside of call() is wrapped by Activity#runOnUiThread() , that is because the callback is always called on another thread from Android UI thread, thus we have to make sure that adding a message to view happens on the UI thread.
Managing Socket State#
Since an Android Activity has its own lifecycle, we should carefully manage the state of the socket also to avoid problems like memory leaks. In this app, we’ll close the socket connection and remove all listeners on onDestroy callback of Activity.
Calling off() removes the listener of the new message event.
Further reading#
If you want to explore more, I recommend you look into:
Other features of this app. They are just implemented with emit() , on() and off() .
Источник
Управляем компьютером с Android устройства
Начало
А началось все с того, что вызывает меня генеральный к себе, и говорит: «Вот видишь телефон? Хочу чтобы там была кнопка, я на нее нажимаю, и у меня в ноутбуке кино включается. Нажимаю другую – музыка играет.» И еще чего-то много наговорил, уж не помню. «Задача понятна? Выполняй!» Вот уж не знаю, с чего такая потребность у него возникла. То ли звезды не под тем углом встали, то ли сон какой приснился. Короче, не поймешь этих богатых… Ну да ладно.
Поначалу полез рыться в Гугл в поисках подходящей программы, а потом подумал – а какого черта? Напишу сам. Тем более, что задача не показалась сложной, да и “зов кода” уже давал о себе знать (этакая профессиональная it-ломка). Вот и решил соединить Windows и Android собственными силами.
То, что он просил, я сделал за пару дней. Но здесь я не хочу городить много кода, проверок и обработок исключений и т.п. Статья скорее предназначена для самых маленьких, как основа, опираясь на которую, можно построить что-то более масштабное. Ни в коем случае не претендую на оригинальность, явно кто-то что-то подобное писал, я просто предлагаю свой вариант. В общем, всем, кому интересно, посвящается.
Что мы имеем
Значит так. С одной стороны, у нас телефон с Android на борту, с другой — Windows с установленными программами, притом некоторые из этих программ нам надо запускать, подав команду с телефона.
Телефон и компьютер свяжем через локальную сеть, тут без вариантов (ну не смски же посылать). Таким образом, будем писать две программы. Первая — это сервер, работающий на компьютере, задача этой программы — открыть и слушать порт. Если на этот порт падает что-то полезное, то выполнить заданное нами действие. Вторая программа — это клиент, запущенный на телефоне, ее задача обработать действия пользователя, подключиться к серверу и передать информацию.
Немного о сокетах
Тема программирование сокетов до того уже заезженная, что и особо говорить нечего. Но все же в двух словах, для тех, кто не любит ходить по ссылкам.
Сокет — это программный интерфейс, который позволяет устанавливать связь между двумя процессами, используя протокол tcp/ip. Сокет ассоциирован с двумя аспектами: ip-адресом и портом. Где ip-адрес — это адрес хоста (компьютера) в сети, с ним работает протокол IP. Port — это идентификатор приложения, к которому адресовано соединение, тут работает протокол TCP. Порт может быть как TCP, так и UDP, в этой статье я буду использовать только TCP. Поскольку ip-адрес является уникальным как в сети интернет, так и в локальной сети, то он однозначно определяет адрес отправителя и адрес принимающего. Порт же является уникальным в пределах операционной системы, он определяет приложение, с которым мы хотим взаимодействовать. Порты могут быть стандартными, например, 80 закреплен за HTTP, или 3389 — RDP. Вы можете использовать любой незанятый порт, но стандартные лучше не трогать. Очень хорошо и с примерами о сокетах написано здесь.
Сервер. Начинаем хулиганить
Запускать Aimp, Windows Media Player и т.п. даже с телефона — это не интересно, да и на базе этой статьи вы сможете все это легко реализовать, немного переделав код. Давайте лучше побезобразничаем. Будим крутить-вертеть экран монитора как нам вздумается или выводит неожиданные сообщения (этакий однонаправленный ацкий мессенджер), и самое ужасное — выключим компьютер! Правда, за это могут и на вилы надеть. Ну да ладно, пускай сначала поймают.
Итак, приступим. В Visual Studio создаем новое Windows Form приложением с именем, скажем, FunnyJoke. Открываем файл Program.cs и удаляем весь код в теле функции Main. Этот код инициализирует главную форму приложения, нашему серверу никакие окна не нужны, он должен сидеть тихо мирно и ждать команд.
В классе Program определим следующие переменные:
Я взял порт 10000, именно его и будет слушать наш сервер, вместо ip адреса задал 0.0.0.0 это говорит о том, что будут обрабатываться все доступные сетевые интерфейсы. Это не совсем правильно, но для начала сойдет. Далее я определил три константы, которые задают коды команд, приходящие от клиента. В начале проекта не забываем подключить:
Теперь, вместо удаленного кода в функции Main вставляем следующий:
Пример хорошо комментирован. Но все же поясню. Сначала создаем локальную конечную точку и ассоциируем ее с нашим ip адресом и портом. Затем, определяем основной сокет, связываем его с конечной точкой, и переводим в режим прослушивания. После этого входим в бесконечный цикл, и начиная со строки:
наш сервер переходит в состояние ожидания соединения. При удачном соединении создастся новый экземпляр Socket, посредствам которого мы и будем общаться с нашим клиентом. После того как соединение установлено начинаем читать данные:
Команды клиента закодированы однобайтовым кодом (описаны в начале программы), сервер расшифровав код команды начинает ее выполнять, после этого снова переходит в режим ожидания. Исключением является codeMsg, т.к. после нее ожидается набор байт, содержащий строку сообщения. Поэтому, получив эту команду сервер снова читает данные с сокета:
Строка, приходящая от клиента, имеет кодировку символов UTF-8, поэтому прежде чем показать ее несчастному пользователю, необходимо привести ее к стандартному виду.
Что бы упростить программу, и не создавать лишние диалоги я использовал стандартный класс MessageBox, но у таков подхода есть один недостаток. MessageBox создает модальное окно, которое блокирует поток всего приложения. Другими словами, пока открыто окно с сообщением наш сервер ничего не делает. Минус конечно, но за простоту надо платить.
Процедуру, изменения ориентации экрана, расписывать не буду, ее код я выполнил так как рекомендует Microsoft вот тут. Как повернуть экран средствами .NET я не нашел. Это легко осуществимо для мобильных платформ, а вот для обычного PC оказалась неразрешимая проблема. Но, на помощь пришел старый добрый WINAPI и все разрулил.
Выключаем компьютер штатными средствами Windows, путем вызова команды shutdown с соответствующими флагами.
С сервером, пожалуй, все. Исходный код проекта я прикреплю в конце статьи.
Клиент
Клиент будем писать в Android Studio, поскольку мне эта IDE больше нравится чем Eclipse. Любителям последнего думаю не составит больших трудностей переделать проект. Для отладки я использовал VirtualBox с установленной виртуальной машиной Android, ибо родной эмулятор жутко тормозной, и жизни не хватить что бы с его помощью что-то отладить. Ну и периодически проверял на «живом» телефоне. Итак, создаем проект с именем FunnyJoke, задаем минимальную версию API, которую способен утянуть ваш телефон (у меня 16) и выбираем Empty Activity. Все остальное по умолчанию. Делаем разметку представления. С дизайном я шибко не извращался, кому надо пускай рисует красивые кнопки, размещает их по фен Шую и т.п. Я сделал просто: два поля типа EditText, первое для ввода ip адреса контролируемого компьютера, второе для текста сообщения, и кнопка, которая заставит поворачиваться рабочий стол. А вот кнопку завершения работы я сделал большую и угрожающее красную. Это чтоб случайно не нажать.
Тут стоит обратить внимание на поле edIPaddress, в нем стоит фильтрация на ввод только цифр и. (точка), так-как поле предназначено для ввода ip адреса. Надо сказать, что это единственная проверка на правильность введенных данных, все остальное остается на совести пользователя. Еще хочу cказать о кнопке btnPowerOff ее состояние отслеживает селектор, и в зависимости от того нажата она или нет меняет изображение (иначе, не понятно произошло ли нажатие, кнопка будет выглядеть как статичная картинка). Вот код селектора button_img.xml:
Соответственно в ресурсах должны быть две картинки одна для нажатого состояния, другая для обычного. Получится вот такой экран:
На этом с разметкой закончим. Переходим к файлу MainActivity.java. В первую очередь, так же, как и в сервере, определяем коды команд и некоторые переменные:
Далее переходим к обработчику нажатия кнопок. Обратите внимание, что обработчик один, и какая копка была нажата определяем по идентификатору. В первую очередь получаем строку с поля edIPaddress, если поле не заполнено, то выводим сообщение о необходимости ввода ip адреса, и больше ничего не делаем.
В Android не рекомендуется создавать долгоиграющие процессы в основном потоке, это связанно с тем, что возможно “подвисание” программы, и пользователь или система может просто закрыть приложение, не дождавшись ответа. К таким долгоиграющим процессам относится и работа с сетью. В этом случае необходимо создать дополнительный поток, в котором и выполнять “долгий” код. В java есть стандартный класс Thread, который позволяет управлять потоками но, его мы использовать не будем, т.к. в Android существует специально предназначенный для этого класс AsyncTask. Подробно можно почитать здесь или здесь.
Создаем класс, который будет заниматься отправкой сообщения, его родителем делаем AsyncTask, и переопределяем метод doInBackground в теле которого и будет находится основной код:
Сначала создаем экземпляр класса InetAddress, который будет содержать в себе ip сервера. Потом создаем сокет, связываем его с удаленным адресом и портом, и запрашиваем стандартный поток ввода/вывода (вернее только вывода, потому что наш клиент ничего не получает). И наконец, в зависимости от значения переменной codeCommand, посылаем сообщение серверу.
Теперь вернемся к нашему обработчику нажатия кнопок, создадим экземпляр класса SenderThread, затем в зависимости от того какая кнопка была нажата инициализируем переменную codeCommand, по ней наш поток будет определять что мы от него хотим. И наконец, активируем, вызвав метод execute().
Немного поправим манифест приложения, дадим разрешение на использование сети и wi-fi, без этого ничего работать не будет:
Все! Можно собирать и проверять. Вот результат:
Источник