- Использование сокетов в 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 Studio Connect to Socket server
- 2 Answers 2
- Сокеты в 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 Studio Connect to Socket server
I have a server running in Java using Eclipse (Here the full code):
As you can see, the client sends 2 values and receives 1, the first one is for the switch, which will indicate what to exceute, for now I just have on option (checking if email exists in the ddbb), the second value is the email as the code has already entered the switch.
The server is fully working and I already tested it with a Client Test project in Eclipse (It is what I want to do in Android Studio):
Now what I want to do is doing the same client in Android Studio so it can connect to the server.
When I run it it does not give me any error but if I log the socket value at doInBackground’s bottom to see the socket value, it says it is null.
I also tried using Thread and Handle but I can’t get the result the server gives me back to the main thread.
2 Answers 2
According to RFC 1918, addresses in the 192.168.0.0-192.168.255.255 range are private. Such addresses can be used internally by any network so they’re often used inside an organization. They cannot be used on the Internet since they aren’t unique. Why my ip address starts with 192.?
I think that your local network is somehow preventing that connection. But without further details nobody can actually tell as far I know.
If you are running everything on the same computer you may want to take a look at «loopback» address. Usually 127.0.0.1 , that should loop back to your machine.
If you want to run a full server you may need to dig more into networking and want to understand how networks function.
I managed to resolve this. I just made a thread inside a «Connection» class in Android Studio.
Inside «Connection» I have some class-level variables, which I use with the thread (The thread can’t modify variables in the method the thread was created but it can read class-level variables) so the thread itself makes the connection with the socket server and saves the value taken to also a class-level variable.
In the main thread (in the same method that called the thread) I used a loop that looks at the thread status, if it has finished, reads the variable and applies it where I want.
I think another possibility could be making the thread just do the connection (and another one for closing it) and saving the socket as class-level variable, so you can send and receive from the main thread, I didn’t try it tho.
Источник
Сокеты в Android
Существует очень много приложений (на Android и на любых других ОС), которые взаимодействуют друг с другом с помощью соединения по сети. Например, к таким приложениям можно отнести любой месседжер: WhatsApp, Viber и т.д. Как правило, соединение между приложениями достигается путём использования сокетов.
Сокеты — это интерфейс, который позволяет связывать между собой различные устройства, находящиеся в одной сети. Сокеты бывают двух типов: клиент и сервер. Различие между ними заключается в том, что сервер прослушивает входящие соединения и обрабатывает поступающие запросы, а клиент к этому серверу подключается. Когда сервер запущен, он начинает прослушивать заданный порт на наличие входящих соединений. Клиент при подключении должен знать IP-адрес сервера и порт.
В связи с этим одним из основных применений сокетов служит использование их в качестве средства коммуникации.
В Android сокеты по умолчанию используют для передачи данных протокол TCP/IP вместо UDP. Важной особенностью этого протокола является гарантированная доставка пакетов с данными от одной конечной точки до другой, что делает этот протокол более надёжным. Протокол UDP не гарантирует доставку пакетов, поэтому этот протокол следует использовать, когда надёжность менее важна, чем скорость передачи.
Для реализации сокетов в Android используются классы Socket, предоставляющий методы для работы с клиентскими сокетами, и ServerSocket, предоставляющий методы для работы с серверными сокетами. Рассмотрим на примере нашего приложения «Эрудит«, как можно реализовать многопоточное приложение на основе сокетов. Суть приложения заключается в том, что в игре принимают участие судья (сервер) и 4 игрока (клиенты). Судья задаёт вопрос, после чего запускает таймер и игроки должны нажать кнопку, ответить на него.
Сервер
В роли сервера здесь будет выступать судья, поскольку он должен принимать ответы от всех команд и контролировать процесс игры. Для начала создадим класс SocketServer, наследующий от Thread.
Примечание: В этом классе неспроста используется наследование от Thread, поскольку операции, связанные с сетью, следует выполнять в отдельном от главного потоке. В противном случае приложение будет крашиться с исключением android.os.NetworkOnMainThreadException. По этой причине здесь и далее вся работа с сокетами будет выполняться в потоках.
Данный класс будет служить «обёрткой» для ServerSocket, чтобы можно было удобнее взаимодействовать с ним. Поскольку мы используем наследование от Thread, необходимо реализовать метод run(), внутри которого будет помещена логика работы сервера.
Задача сервера заключается в том, чтобы слушать заданный порт и принимать входящие подключения. Однако поскольку у нас должно быть 4 клиента, их нужно как-то различать. Для этих целей создадим класс UserManager, целью которого будет связывание сокета, полученного в результате метода accept() с пользователем, который установил соединение.
Здесь аналогичным образов в потоке запускаем созданный сокет и ставим его на прослушивание. Параллельно с этим создаём экземпляр класса User, код которого представлен ниже. Он служит для хранения данных о пользователях и их сообщениях
После того, как сообщение было получено, проверяется наличие в нём команд в методе hasCommand(). Например, команда LOGIN_NAME сообщает никнейм подключившегося игрока, а команда CLOSED_CONNECTION — о закрытии соединения. Если никакой команды нет — просто передаём сообщение через интерфейс.
При подключении нового пользователя передаём в интерфейс данные о нём с помощью метода userConnected(), аналогично при дисконнекте вызываем userDisconnected().
Метод close() закрывает соединение с клиентом.
Метод sendMessage() отправляет сообщение клиенту.
Теперь пробросим интерфейс в класс SocketServer.
В SocketServer создадим экземпляр класса UserManager и список, содержащий объекты этого класса. При создании нового сокета он передаётся в конструктор UserManager, после чего запускается поток.
Чтобы остановить сервер, напишем метод close() со следующим кодом.
Для начала здесь нужно закрыть все соединения с клиентами, после этого остановить прослушивание и остановить сокет методом close().
Отправка сообщений клиентам происходит следующим образом.
Метод sendMessage() отправляет сообщение всем, кроме выбранного пользователя. Он используется, когда отправляется сообщение о том, что отвечает команда N, другим командам.
Метод sendMessageTo() отправляет сообщение только одному пользователю, поиск пользователя происходит по идентификатору.
Метод sendToAll() отправляет сообщение всем подключённым пользователям.
Теперь нужно создать интерфейс, который будет передавать данные в основной поток. Для этого создадим интерфейс со следующим кодом.
Теперь в главном потоке нужно создать экземпляр класса SocketServer и пробросить интерфейс.
Метод updatePlayer() обновляет список подключенных игроков при подключении\отключении кого-либо из игроков.
Примечание: если из потока нужно обновить элементы интерфейса, то следует вызывать runOnUiThread(), который позволяет выполнять код в UI-потоке.
Метод parseMessage() определяет, что за сообщение пришло. Сначала следует проверка на то, что на вопрос уже даётся ответ. В этом случае игроку, отправившему это сообщение, отправляется ответ о том, что на вопрос уже даётся ответ. После этого идёт проверка на то, запущен ли таймер. Если таймер не был запущен, то необходимо отправить игроку сообщение о фальстарте. После всех проверок определяется, какой пользователь отправил сообщение и загорается соответствующая кнопка на экране.
Примечание: поскольку отправлять сообщения в UI-потоке нельзя, здесь используется следующая конструкция.
Клиент
Клиент это игрок, который отвечает на вопрос, заданный судьёй. После сигнала он должен нажать на кнопку, чтобы дать ответ на вопрос.
Для реализации клиентского сокета создадим класс SocketClient.
Метод run() запускает клиент и содержит логику работы сокета. Внутри него создаётся экземпляр класса Socket, который подключается к конечной точке с заданными IP-адресом и портом. Затем вызывается метод onConnected() интерфейса OnMessageReceived, уведомляющий главный поток о том, что сокет установил соединение. После этого вызывается метод sendMessage(), отправляющий сообщения на сервер, в котором передаётся команда LOGIN_NAME и название команды. После этого запускается бесконечный цикл, в котором клиент ждёт сообщения от сервера. Получив сообщение, происходит вызов метода messageReceived() интерфейса OnMessageReceived, который передает сообщение в главный поток.
Метод isConnected() проверяет, подключился ли клиент к серверу.
Метод isRunning() проверяет, запущен ли клиент.
Метод stopClient() разрывает соединение с сервером, предварительно посылая сообщение с командой CLOSED_CONNECTION.
Теперь создадим на активности экземпляр класса SocketClient и пробросим интерфейс.
После того, как будут заданы название команды и IP-адрес сервера, запустится метод connectToServer(), создающий поток, в котором инициализируется экземпляр SocketClient. Внутри него реализован интерфейс с методами onConnected() и messageReceived().
В методе onConnected() мы получаем событие, что клиент установил соединение, и вызываем метод sendPing(), который будет каждые 2 секунды посылать на сервер пинги. Это необходимо для более надежного соединения, поскольку отследить на стороне клиента, что сервер прекратил работу, может быть весьма затруднительно. В случае, если соединение теряется, начинает вызываться метод connectToServer() до тех пор, пока соединение не восстановится.
В методе messageReceived() определяется, какое сообщение пришло от сервера, и в зависимости от этого выполняются соответствующие операции.
- ANSWERED — уведомляет о том, что она вопрос уже отвечает другая команда. Возвращает кнопку в исходное состояние.
- BEEP — сообщает о том, что таймер был запущен и нужно воспроизвести сигнал. Для этого вызывается метод playBeep(), который с помощью класса MediaPlayer воспроизводит MP3-файл, хранящийся в папке Assets.
- RESET — сбрасывает все данные (поле ответа от сервера, состояние кнопки). Это сообщение приходит, когда какая-либо команда ответила на вопрос и нужно восстановить все состояния для нового вопроса.
- FALSE_START — сообщает игроку, что он нажал кнопку раньше, чем был запущен таймер. Возвращает кнопку в исходное состояние.
- По умолчанию: просто выводит сообщение от сервера на экран.
Когда вызывается метод активности onPause(), клиент останавливается с помощью следующего кода.
При возврате в активность восстановить соединение можно вручную, нажать на кнопку переподключения, которая вызовет метод connectToServer().
Сообщение об ответе на сервер посылается с помощью метода sendAnswer(), который вызывается при нажатии на кнопку.
Таким образом, в результате приведенного выше кода мы создали приложение, работающее на сокетах, которые обеспечивают взаимодействие между сервером и несколькими клиентами.
Источник