Android java connect server

Sending and Receiving Data with Sockets in android

Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project.

Step 2 − Add the following code to res/layout/activity_main.xml.

Step 3 − Add the following code to src/MainActivity.java

package com.server.myapplication.server; import android.annotation.SuppressLint; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @SuppressLint("SetTextI18n") public class MainActivity extends AppCompatActivity < ServerSocket serverSocket; Thread Thread1 = null; TextView tvIP, tvPort; TextView tvMessages; EditText etMessage; Button btnSend; public static String SERVER_IP = ""; public static final int SERVER_PORT = 8080; String message; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvIP = findViewById(R.id.tvIP); tvPort = findViewById(R.id.tvPort); tvMessages = findViewById(R.id.tvMessages); etMessage = findViewById(R.id.etMessage); btnSend = findViewById(R.id.btnSend); try < SERVER_IP = getLocalIpAddress(); >catch (UnknownHostException e) < e.printStackTrace(); >Thread1 = new Thread(new Thread1()); Thread1.start(); btnSend.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View v) < message = etMessage.getText().toString().trim(); if (!message.isEmpty()) < new Thread(new Thread3(message)).start(); >> >); > private String getLocalIpAddress() throws UnknownHostException < WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE); assert wifiManager ! = null; WifiInfo wifiInfo = wifiManager.getConnectionInfo(); int ipInt = wifiInfo.getIpAddress(); return InetAddress.getByAddress(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(ipInt).array()).getHostAddress(); >private PrintWriter output; private BufferedReader input; class Thread1 implements Runnable < @Override public void run() < Socket socket; try < serverSocket = new ServerSocket(SERVER_PORT); runOnUiThread(new Runnable() < @Override public void run() < tvMessages.setText("Not connected"); tvIP.setText("IP: " + SERVER_IP); tvPort.setText("Port: " + String.valueOf(SERVER_PORT)); >>); try < socket = serverSocket.accept(); output = new PrintWriter(socket.getOutputStream()); input = new BufferedReader(new InputStreamReader(socket.getInputStream())); runOnUiThread(new Runnable() < @Override public void run() < tvMessages.setText("Connected
"); > >); new Thread(new Thread2()).start(); > catch (IOException e) < e.printStackTrace(); >> catch (IOException e) < e.printStackTrace(); >> > private class Thread2 implements Runnable < @Override public void run() < while (true) < try < final String message = input.readLine(); if (message ! = null) < runOnUiThread(new Runnable() < @Override public void run() < tvMessages.append("client:" + message + "
"); > >); > else < Thread1 = new Thread(new Thread1()); Thread1.start(); return; >> catch (IOException e) < e.printStackTrace(); >> > > class Thread3 implements Runnable < private String message; Thread3(String message) < this.message = message; >@Override public void run() < output.write(message); output.flush(); runOnUiThread(new Runnable() < @Override public void run() < tvMessages.append("server: " + message + "
"); etMessage.setText(""); > >); > > >

Step 4 − Add the following code to androidManifest.xml

Client

Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project.

Step 2 − Add the following code to res/layout/activity_main.xml.

Step 3 − Add the following code to res/layout/MainActivity.java.

package com.client.myapplication.client; import android.annotation.SuppressLint; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; @SuppressLint("SetTextI18n") public class MainActivity extends AppCompatActivity < Thread Thread1 = null; EditText etIP, etPort; TextView tvMessages; EditText etMessage; Button btnSend; String SERVER_IP; int SERVER_PORT; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etIP = findViewById(R.id.etIP); etPort = findViewById(R.id.etPort); tvMessages = findViewById(R.id.tvMessages); etMessage = findViewById(R.id.etMessage); btnSend = findViewById(R.id.btnSend); Button btnConnect = findViewById(R.id.btnConnect); btnConnect.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View v) < tvMessages.setText(""); SERVER_IP = etIP.getText().toString().trim(); SERVER_PORT = Integer.parseInt(etPort.getText().toString().trim()); Thread1 = new Thread(new Thread1()); Thread1.start(); >>); btnSend.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View v) < String message = etMessage.getText().toString().trim(); if (!message.isEmpty()) < new Thread(new Thread3(message)).start(); >> >); > private PrintWriter output; private BufferedReader input; class Thread1 implements Runnable < public void run() < Socket socket; try < socket = new Socket(SERVER_IP, SERVER_PORT); output = new PrintWriter(socket.getOutputStream()); input = new BufferedReader(new InputStreamReader(socket.getInputStream())); runOnUiThread(new Runnable() < @Override public void run() < tvMessages.setText("Connected
"); > >); new Thread(new Thread2()).start(); > catch (IOException e) < e.printStackTrace(); >> > class Thread2 implements Runnable < @Override public void run() < while (true) < try < final String message = input.readLine(); if (message ! = null) < runOnUiThread(new Runnable() < @Override public void run() < tvMessages.append("server: " + message + "
"); > >); > else < Thread1 = new Thread(new Thread1()); Thread1.start(); return; >> catch (IOException e) < e.printStackTrace(); >> > > class Thread3 implements Runnable < private String message; Thread3(String message) < this.message = message; >@Override public void run() < output.write(message); output.flush(); runOnUiThread(new Runnable() < @Override public void run() < tvMessages.append("client: " + message + "
"); etMessage.setText(""); > >); > > >

Step 4 − Add the following code to androidManifest.xml

Читайте также:  Png to swf php

Let’s try to run your both server and client application. I assume you have connected your actual Android Mobile device with your computer. To run the app from android studio, open one of your project’s activity files and click Run icon from the toolbar. Select your mobile device as an option and then check your mobile device which will display your default screen –

Click here to download the project code

Источник

Использование сокетов в 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

import android.util.Log; import java.io.IOException; import java.net.Socket; public class Connection < private Socket mSocket = null; private String mHost = null; private int mPort = 0; public static final String LOG_TAG = "SOCKET"; public Connection() <>public Connection (final String host, final int port) < this.mHost = host; this.mPort = port; >// Метод открытия сокета public void openConnection() throws Exception < // Если сокет уже открыт, то он закрывается closeConnection(); try < // Создание сокета mSocket = new Socket(mHost, mPort); >catch (IOException e) < throw new Exception("Невозможно создать сокет: " + e.getMessage()); >> /** * Метод закрытия сокета */ public void closeConnection() < if (mSocket != null && !mSocket.isClosed()) < try < mSocket.close(); >catch (IOException e) < Log.e(LOG_TAG, "Ошибка при закрытии сокета :" + e.getMessage()); >finally < mSocket = null; >> mSocket = null; > /** * Метод отправки данных */ public void sendData(byte[] data) throws Exception < // Проверка открытия сокета if (mSocket == null || mSocket.isClosed()) < throw new Exception("Ошибка отправки данных. " + "Сокет не создан или закрыт"); >// Отправка данных try < mSocket.getOutputStream().write(data); mSocket.getOutputStream().flush(); >catch (IOException e) < throw new Exception("Ошибка отправки данных : " + e.getMessage()); >> @Override protected void finalize() throws Throwable < super.finalize(); closeConnection(); >>

Класс активности MainActivity

В активности MainActivity определены параметры сервера : host, port. Помните, что IP-адрес сервера для Вашего android-примера не может быть localhost (127.0.0.1), иначе Вы будете пытаться связаться с сервером внутри Andriod-системы. Кнопки интерфейса связаны с методами обращения к классу Connection. Кнопки отправки сообщения mBtnSend и закрытия соединения mBtnClose с сервером блокируются при старте приложения. После установления соединения с сервером доступ к кнопкам открывается.

Читайте также:  Читать построчно csv файл python

Листинг активности

public class MainActivity extends AppCompatActivity < private Button mBtnOpen = null; private Button mBtnSend = null; private Button mBtnClose = null; private EditText mEdit = null; private Connection mConnect = null; private String HOST = "10.120.51.22"; private int PORT = 9876; private String LOG_TAG = "SOCKET"; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBtnOpen = (Button) findViewById(R.id.btn_open ); mBtnSend = (Button) findViewById(R.id.btn_send ); mBtnClose = (Button) findViewById(R.id.btn_close); mEdit = (EditText) findViewById(R.id.edText ); mBtnSend .setEnabled(false); mBtnClose.setEnabled(false); mBtnOpen.setOnClickListener(new OnClickListener() < @Override public void onClick(View v) < onOpenClick(); >>); mBtnSend.setOnClickListener(new OnClickListener() < @Override public void onClick(View v) < onSendClick(); >>); mBtnClose.setOnClickListener(new OnClickListener() < @Override public void onClick(View v) < onCloseClick(); >>); > >

Методы управления сокетным соединением

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

private void onOpenClick() < // Создание подключения mConnect = new Connection(HOST, PORT); // Открытие сокета в отдельном потоке new Thread(new Runnable() < @Override public void run() < try < mConnect.openConnection(); // Разблокирование кнопок в UI потоке runOnUiThread(new Runnable() < @Override public void run() < mBtnSend.setEnabled(true); mBtnClose.setEnabled(true); >>); Log.d(LOG_TAG, "Соединение установлено"); Log.d(LOG_TAG, "(mConnect != null) = " + (mConnect != null)); > catch (Exception e) < Log.e(LOG_TAG, e.getMessage()); mConnect = null; >> >).start(); > private void onSendClick() < if (mConnect == null) < Log.d(LOG_TAG, "Соединение не установлено"); >else < Log.d(LOG_TAG, "Отправка сообщения"); new Thread(new Runnable() < @Override public void run() < try < String text; text = mEdit.getText().toString(); if (text.trim().length() == 0) text = "Test message"; // отправляем сообщение mConnect.sendData(text.getBytes()); >catch (Exception e) < Log.e(LOG_TAG, e.getMessage()); >> >).start(); > > private void onCloseClick() < // Закрытие соединения mConnect.closeConnection(); // Блокирование кнопок mBtnSend .setEnabled(false); mBtnClose.setEnabled(false); Log.d(LOG_TAG, "Соединение закрыто"); >

Серверное приложение

Серверное приложение включает 2 класса : Server и ConnectionWorker. Серверный класс Server будет выполнять обработку взаимодействия с клиентом с использованием ConnectionWorker в отдельном потоке. Конструктор ConnectionWorker в качестве параметра получает объект типа Socket для чтения сообщений клиента из потока сокета.

Листинг ConnectionWorker

ConnectionWorker получает входной поток inputStream из клиентского сокета и читает сообщение. Если сообщение отсутствует, т.е. количество прочитанных байт равно -1, то это значит, что соединение разорвано, то клиентский сокет закрывается. При закрытии клиентского соединения входной поток сокета также закрывается.

public class ConnectionWorker implements Runnable < // Сокет для взаимодействия с клиентом private Socket clientSocket = null; // Входной поток получения данных из сокета private InputStream inputStream = null; public ConnectionWorker(Socket socket) < clientSocket = socket; >@Override public void run() < try < // Определение входного потока inputStream = clientSocket.getInputStream(); >catch (IOException e) < System.err.println("Can't get input stream"); >// Буфер для чтения информации byte[] data = new byte[1024*4]; while(true) < try < /* * Получение информации : * count - количество полученных байт */ int count; count=inputStream.read(data,0,data.length); if (count >0) < String msg=new String(data, 0, count); // Вывод в консоль сообщения System.out.println(msg); >else if (count == -1 ) < // Если count=-1, то поток прерван System.out.println("socket is closed"); clientSocket.close(); break; >> catch (IOException e) < System.err.println(e.getMessage()); >> System.out.println("ConnectionWorker stoped"); > >

Серверный класс

Серверный класс Server создадим с использованием многопоточного пакета util.concurrent. На странице описания сетевого пакета java.net и серверного ServerSocket был приведен пример серверного модуля с использованием обычного потока Thread, при работе с которым необходимо решать задачу его остановки : cтарый метод Thread.stop объявлен Deprecated и предан строжайшей анафеме, а безопасная инструкция Thread.interrupt безопасна, к сожалению, потому, что ровным счетом ничего не делает (отправляет сообщение потоку : «Пожалуйста, остановись»). Услышит ли данный призыв поток остается под вопросом – все зависит от разаработчика.

Читайте также:  Java util log handler

Чтобы иметь возможность остановить сервер «снаружи» в серверный класс Server включим 2 внутренних реализующих интерфейс Callable класса : CallableDelay и CallableServer. Класс CallableDelay будет функционировать определенное время, по истечении которого завершит свою работу и остановит 2-ой серверный поток взаимодействия с клиентами. В данном примере CallableDelay используется только для демонстрации остановки потока, организуемого пакетом util.concurrent.

Листинг CallableDelay

CallableDelay организует цикл с задержками. После завершения последнего цикла cycle поток завершает цикл, останавливает вторую задачу futureTask[1] и закрывает сокет. В консоль выводится соответствующее сообщение.

class CallableDelay implements Callable  < private int cycle; public CallableDelay(int cycle) < this.cycle = cycle; >@Override public String call() throws Exception < while (cycle >0) < System.out.println("" + cycle); Thread.sleep(1000); cycle--; >// Останов 2-ой задачи futureTask[1].cancel(true); // Закрытие серверного сокета serverSoket.close(); System.out.println("Thread '" + Thread.currentThread().getName() + "' stoped" ); // Наименование потока, выполняющего задачу return "" + Thread.currentThread().getName(); > >

Листинг CallableServer

Конструктор CallableServer в качестве параметров получает значение открываемого порта для подключения клиентов. При старте (метод call) создается серверный сокет ServerSocket и поток переходит в режим ожидания соединения с клиентом. Остановить поток можно вызовом метода stopTask, либо завершением «задачи» типа FutureTask с данным потоком.

При подключении клиента метод serverSoket.accept возвращает сокет, который используется для создания объекта ConnectionWorker и его запуска в отдельном потоке. А сервер (поток) переходит к ожиданию следующего подключения.

В случае закрытия сокета (завершение внешней задачи FutureTask с данным потоком) будет вызвано исключение Exception, где выполняется проверка закрытия сокета; при положительном ответе основной цикл прерывается и поток завершает свою работу.

class CallableServer implements Callable  < private int port; private boolean started; public CallableServer(int port) < this.port = port; this.started = true; >public void stopTask() < started = false; >@Override public String call() throws Exception < // Создание серверного сокета serverSoket = new ServerSocket(port); System.out.println("Server start on port : " + port); // Цикл ожидания соединений клиентов с сервером while(started) < ConnectionWorker worker = null; try < // Ожидание соединения с клиентом worker = new ConnectionWorker( serverSoket.accept()); /* * Обработка соединения выполняется * в отдельном потоке */ Thread t = new Thread(worker); t.start(); >catch (Exception e) < System.err.println("Connection error : " + e.getMessage()); // Завершение цикла. if (serverSoket.isClosed()) break; >> System.out.println("Thread '" + Thread.currentThread().getName() + "' stoped" ); futureTask[1].cancel(true); // Наименование потока, выполняющего задачу return "" + Thread.currentThread().getName(); > >

Листинг серверного класса Server

Cерверный класс Server создает два потоковых объекта (callable1, callable2), формирует из них две задачи futureTask и запускает задачи на выполнение методом execute исполнителя executor. После этого контролируется завершение выполнение обоих задач методом isTasksDone. При завершении выполнения обеих задач завершается также и цикл работы executor’а.

Два внутренних описанных выше класса (CallableDelay, CallableServer) не включены в листинг.

public class Server < // Открываемый сервером порт для клиентов private final int SERVER_PORT = 9876; // Сокет соединения с клиентами private ServerSocket serverSoket = null; // Поток контроля времени работы сервера private CallableDelay callable1 = null; // Поток соединения с клиентами private CallableServer callable2 = null; // Список задач private FutureTask[] futureTask = null; // Исполнитель задач private ExecutorService executor = null; private Server() < // 1-ый поток контролирует задержку работы сервера callable1 = new CallableDelay (50); // 2-йй поток открывает соединение callable2 = new CallableServer(SERVER_PORT); // Создание задач futureTask = new FutureTask[2]; futureTask[0] = new FutureTask(callable1); futureTask[1] = new FutureTask(callable2); // Выполнение задач executor = Executors.newFixedThreadPool(2); executor.execute(futureTask[0]); executor.execute(futureTask[1]); // Цикл работы executor'а while (true) < if (isTasksDone()) < // Завершение работы executor'а executor.shutdown(); System.out.println("\nexecutor shutdown"); break; >> > //----------------------------------------------------- private boolean isTasksDone() < return futureTask[0].isDone() && futureTask[1].isDone(); >//----------------------------------------------------- public static void main(String[] args) < new Server(); >>

Скачать пример

Архив примера android-socket.zip (98 Кб) включает два проекта : клиентский android (client-android/p12socket) и серверный server-eclipse.

Источник

Оцените статью