Client-Server Programming in Android. Send Message to the Client and Back.

By | May 1, 2017

Hi all, Today I will show you how you can implement Client-Server architecture in an Android environment.

Android Socket Programming

What is a socket?

A socket is an interface between application and network.
The socket type dictates the style of communication reliable vs. best effort connection-oriented vs. connectionless. Once configured the application can pass data to the socket for network transmission receive data from the socket (transmitted through the network by some other host).

A socket is a software end-point of an application.
By using a Socket a process in one system can communicate with another process in a system.

Lets see here how we can do this in Android.

I will have two projects. One is a Server program and other one is the Client.
Once you run both programs in two different devices. You need to Start the server in the Server device. Now the Client device will send a message to connect and it gets connected. Now a socket connection is established. Now you can send messages in both directions using this Socket Connection.

Note : To Connect between sockets, both devices has to be in the same network (for eg : same Wi-Fi).
Also you have to replace the IP in the client program with the server IP.

You can find the IP of an Android device by navigating to the Wifi Settings -> Menu -> Advanced.

Add permission

	 <uses-permission android:name="android.permission.INTERNET" />

Server

Layout

This will contain a button to start the server and another button to send a message to the server.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_server" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.vipin.socketdemo.ServerActivity">

    <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:text="Server" />

    <Button android:id="@+id/start_server" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="onClick" android:text="Start Server" />

    <Button android:id="@+id/send_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="onClick" android:text="Send Message to Client" />

    <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content">

        <TextView android:id="@+id/messageTv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="No Messages" />
    </ScrollView>

</LinearLayout>

Server Activity


import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    public static final String TAG = MainActivity.class.getSimpleName();

    private ServerSocket serverSocket;
    private Socket tempClientSocket;
    Thread serverThread = null;
    public static final int SERVER_PORT = 3000;
    TextView messageTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_server);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        messageTv = (TextView) findViewById(R.id.messageTv);
    }

    public void updateMessage(final String message) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                messageTv.append(message + "\n");
            }
        });
    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.start_server) {
            Log.d(TAG, "Starting Server...");
            messageTv.setText("");
            updateMessage("Starting Server...");
            this.serverThread = new Thread(new ServerThread());
            this.serverThread.start();
            return;
        }
        if (view.getId() == R.id.send_data) {
            sendMessage("Hello from Server...");
        }
    }

    private void sendMessage(String message) {
        try {
            if (null != tempClientSocket) {
                PrintWriter out = new PrintWriter(new BufferedWriter(
                        new OutputStreamWriter(tempClientSocket.getOutputStream())),
                        true);
                out.println(message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    class ServerThread implements Runnable {

        public void run() {
            Socket socket;
            try {
                serverSocket = new ServerSocket(SERVER_PORT);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (null != serverSocket) {
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        socket = serverSocket.accept();
                        CommunicationThread commThread = new CommunicationThread(socket);
                        new Thread(commThread).start();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    class CommunicationThread implements Runnable {

        private Socket clientSocket;

        private BufferedReader input;

        public CommunicationThread(Socket clientSocket) {

            this.clientSocket = clientSocket;
            tempClientSocket = clientSocket;

            try {
                this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
            } catch (IOException e) {
                e.printStackTrace();
            }

            updateMessage("Server Started...");
        }

        public void run() {

            while (!Thread.currentThread().isInterrupted()) {

                try {

                    String read = input.readLine();
                    Log.i(TAG, "Message Received from Client : " + read);

                    if (null == read || "Disconnect".contentEquals(read)) {
                        Thread.interrupted();
                        read = "Client Disconnected";
                        updateMessage(getTime() + " | Client : " + read);
                        break;
                    }
                    updateMessage(getTime() + " | Client : " + read);

                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }

    }

    String getTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        return sdf.format(new Date());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (null != serverThread) {
            sendMessage("Disconnect");
            serverThread.interrupt();
            serverThread = null;
        }
    }
}


Client

Layout

Client Layout will contain a button to send a message to server.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_server" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin">

    <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Client" android:layout_marginBottom="10dp"/>

    <Button android:id="@+id/connect_server" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="onClick" android:text="Connect to server" />

    <Button android:id="@+id/send_data" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="onClick" android:text="Send Message to server" />

    <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content">

        <TextView android:id="@+id/messageTv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="No Messages" />
    </ScrollView>


</LinearLayout>

Client Activity


import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Client extends AppCompatActivity implements View.OnClickListener {

    public static final String TAG = Client.class.getSimpleName();

    public static final int SERVERPORT = 3000;

    public static final String SERVER_IP = "YOUR_SERVER_IP";
    ClientThread clientThread;
    Thread thread;
    TextView messageTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        messageTv = (TextView) findViewById(R.id.messageTv);
    }

    public void updateMessage(final String message) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                messageTv.append(message + "\n");
            }
        });
    }

    @Override
    public void onClick(View view) {

        if (view.getId() == R.id.connect_server) {
            messageTv.setText("");
            clientThread = new ClientThread();
            thread = new Thread(clientThread);
            thread.start();
            return;
        }

        if (view.getId() == R.id.send_data) {
            clientThread.sendMessage("Hello from Client");
        }
    }

    class ClientThread implements Runnable {

        private Socket socket;
        private BufferedReader input;

        @Override
        public void run() {

            try {
                InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
                socket = new Socket(serverAddr, SERVERPORT);

                while (!Thread.currentThread().isInterrupted()) {

                    Log.i(TAG, "Waiting for message from server...");

                    this.input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    String message = input.readLine();
                    Log.i(TAG, "Message received from the server : " + message);

                    if (null == message || "Disconnect".contentEquals(message)) {
                        Thread.interrupted();
                        message = "Server Disconnected.";
                        updateMessage(getTime() + " | Server : " + message);
                        break;
                    }

                    updateMessage(getTime() + " | Server : " + message);

                }

            } catch (UnknownHostException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            }

        }

        void sendMessage(String message) {
            try {
                if (null != socket) {
                    PrintWriter out = new PrintWriter(new BufferedWriter(
                            new OutputStreamWriter(socket.getOutputStream())),
                            true);
                    out.println(message);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }


        }

    }

    String getTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        return sdf.format(new Date());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (null != clientThread) {
            clientThread.sendMessage("Disconnect");
            clientThread = null;
        }
    }
}

If Client or Server exits, it sends a “Disconnect” command. By this way the peer will know that the other process has disconnected.

Source Code.

You can download the complete source code from here.

18 thoughts on “Client-Server Programming in Android. Send Message to the Client and Back.

  1. Ezra Alvaro Manuel

    Hi, James, This is great!,
    but i have 1 question,
    for example if i want to make the textview message received replaced by the new message without print it to the next line, what should i do?

    Reply
    1. James Post author

      Ezra,

      You could just go a messageTv.setText() on the textview instead of messageTv.append().

      Reply
  2. Sanyi

    Hi,
    Is it possible to connect two devices from different networks, please?

    Reply
    1. James Post author

      Yes, it is possible, but you network should allow outbound connections through that specific port.

      Reply
  3. cogoree

    Hi thanks a lot for your example code.
    I have a one question.
    There is your code “socket = serverSocket.accept();”
    That’s where the code doesn’t work.
    What can I do?

    Reply
    1. James Post author

      cogoree, What is the error you are getting? You port should allow the socket connection and if not you should be in the same wifi network.

      Reply
      1. Dilip

        I am also having issue from this code , is there any solution here. It doesn’t log any things.

        Reply
  4. Dhaval Modi

    can I use this code by creating a hotspot in the device I’m using as server?

    Reply
  5. amy

    how would you change your server code if the server was a raspberry pi?
    the client is android

    Reply
  6. Pravinsingh Waghela

    Nothing happening.
    It shows Only Starting Server…
    I have changed the IP Address in both Server and Client App with my Server Device IP address. But not working.

    Reply
    1. James Post author

      Are you on the same Wifi Network or you should have a PORT open for communication.

      Reply
  7. Olivetree

    Same Wifi Network , changed the server IP Address , compileSdkVersion 25, buildToolsVersion “25.0.2”
    There are no errors, but nothing happening.!!! I do not know why it does not work.
    Do I need to request additional Java programs as the version is upgraded?
    Please help me

    Reply
  8. Olivetree

    Hi,
    I changed the IP Address in both Server and Client App and using same WiFi network
    But nothing happening.
    classpath ‘com.android.tools.build:gradle:2.2.3’ compileSdkVersion 25
    buildToolsVersion “25.0.2” do not know why it does not work.
    Is it possible that the version is up and that system approval is needed?
    please answer about my question.

    Reply
  9. Olivetree

    Hi,
    I changed the IP Address in both Server and Client App and using same WiFi network
    But nothing happening.
    classpath ‘com.android.tools.build:gradle:2.2.3’ compileSdkVersion 25
    buildToolsVersion “25.0.2” do not know why it does not work.
    Is it possible that the version is up and that system approval is needed?
    please answer about my question.

    Reply
    1. James Post author

      Are you using the port that is allowed and not a reserved one like 8080 for http?

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *