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.

 
Watch Video Demo

 
Below is the demo of the app we are going to build.

 
Watch Video Tutorial

 

I wil be explaining the code in the below video tutorial. If you have any comments, please leave it below the video in the comments section.

 
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 have two projects here. 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 first. Then Client device will send a message to connect and it gets connected. Once it is connected, that means that 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 (OrĀ  this will be your actual server IP with the opened port specifically for communication with your device).

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"?>
<RelativeLayout 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:padding="20dp"
    tools:context=".ServerActivity">

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

    <EditText
        android:id="@+id/edMessage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/start_server"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:text="Message from Server" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/send_data"
        android:layout_below="@+id/edMessage">

        <LinearLayout
            android:id="@+id/msgList"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical">

        </LinearLayout>

    </ScrollView>

    <Button
        android:id="@+id/send_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@drawable/button_pressed"
        android:onClick="onClick"
        android:text="Send Message to Client"
        android:textColor="@android:color/white" />

</RelativeLayout>

Server Activity

We are going to build the Server App first, so this will be the MainActivity for this project.

package com.coderzheaven.clientserverdemo;

import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
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 ServerActivity extends AppCompatActivity implements View.OnClickListener {

    private ServerSocket serverSocket;
    private Socket tempClientSocket;
    Thread serverThread = null;
    public static final int SERVER_PORT = 3003;
    private LinearLayout msgList;
    private Handler handler;
    private int greenColor;
    private EditText edMessage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_server);
        setTitle("Server");
        greenColor = ContextCompat.getColor(this, R.color.green);
        handler = new Handler();
        msgList = findViewById(R.id.msgList);
        edMessage = findViewById(R.id.edMessage);
    }

    public TextView textView(String message, int color) {
        if (null == message || message.trim().isEmpty()) {
            message = "<Empty Message>";
        }
        TextView tv = new TextView(this);
        tv.setTextColor(color);
        tv.setText(message + " [" + getTime() +"]");
        tv.setTextSize(20);
        tv.setPadding(0, 5, 0, 0);
        return tv;
    }

    public void showMessage(final String message, final int color) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                msgList.addView(textView(message, color));
            }
        });
    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.start_server) {
            msgList.removeAllViews();
            showMessage("Server Started.", Color.BLACK);
            this.serverThread = new Thread(new ServerThread());
            this.serverThread.start();
            return;
        }
        if (view.getId() == R.id.send_data) {
            String msg = edMessage.getText().toString().trim();
            showMessage("Server : " + msg, Color.BLUE);
            sendMessage(msg);
        }
    }

    private void sendMessage(final String message) {
        try {
            if (null != tempClientSocket) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        PrintWriter out = null;
                        try {
                            out = new PrintWriter(new BufferedWriter(
                                    new OutputStreamWriter(tempClientSocket.getOutputStream())),
                                    true);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        out.println(message);
                    }
                }).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    class ServerThread implements Runnable {

        public void run() {
            Socket socket;
            try {
                serverSocket = new ServerSocket(SERVER_PORT);
                findViewById(R.id.start_server).setVisibility(View.GONE);
            } catch (IOException e) {
                e.printStackTrace();
                showMessage("Error Starting Server : " + e.getMessage(), Color.RED);
            }
            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();
                        showMessage("Error Communicating to Client :" + e.getMessage(), Color.RED);
                    }
                }
            }
        }
    }

    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();
                showMessage("Error Connecting to Client!!", Color.RED);
            }
            showMessage("Connected to Client!!", greenColor);
        }

        public void run() {

            while (!Thread.currentThread().isInterrupted()) {
                try {
                    String read = input.readLine();
                    if (null == read || "Disconnect".contentEquals(read)) {
                        Thread.interrupted();
                        read = "Client Disconnected";
                        showMessage("Client : " + read, greenColor);
                        break;
                    }
                    showMessage("Client : " + read, greenColor);
                } 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

Now that server is done, we are going to create files for the client project. Make sure both are different projects for better understanding.

Layout

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

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_server"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="20dp">

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

    <EditText
        android:id="@+id/edMessage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/connect_server"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:text="Message from Client" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/send_data"
        android:layout_below="@+id/edMessage">

        <LinearLayout
            android:id="@+id/msgList"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical" />

    </ScrollView>

    <Button
        android:id="@+id/send_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@drawable/button_pressed"
        android:onClick="onClick"
        android:text="Send Message to server"
        android:textColor="@android:color/white" />

</RelativeLayout>

Client Activity


package com.coderzheaven.clientapplication;

import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
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.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ClientActivity extends AppCompatActivity implements View.OnClickListener {

    public static final int SERVERPORT = 3003;

    public static final String SERVER_IP = "YOUR_SERVER_IP";
    private ClientThread clientThread;
    private Thread thread;
    private LinearLayout msgList;
    private Handler handler;
    private int clientTextColor;
    private EditText edMessage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_client);

        setTitle("Client");
        clientTextColor = ContextCompat.getColor(this, R.color.green);
        handler = new Handler();
        msgList = findViewById(R.id.msgList);
        edMessage = findViewById(R.id.edMessage);
    }

    public TextView textView(String message, int color) {
        if (null == message || message.trim().isEmpty()) {
            message = "<Empty Message>";
        }
        TextView tv = new TextView(this);
        tv.setTextColor(color);
        tv.setText(message + " [" + getTime() + "]");
        tv.setTextSize(20);
        tv.setPadding(0, 5, 0, 0);
        return tv;
    }

    public void showMessage(final String message, final int color) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                msgList.addView(textView(message, color));
            }
        });
    }

    @Override
    public void onClick(View view) {

        if (view.getId() == R.id.connect_server) {
            msgList.removeAllViews();
            showMessage("Connecting to Server...", clientTextColor);
            clientThread = new ClientThread();
            thread = new Thread(clientThread);
            thread.start();
            showMessage("Connected to Server...", clientTextColor);
            return;
        }

        if (view.getId() == R.id.send_data) {
            String clientMessage = edMessage.getText().toString().trim();
            showMessage(clientMessage, Color.BLUE);
            if (null != clientThread) {
                clientThread.sendMessage(clientMessage);
            }
        }
    }

    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()) {

                    this.input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    String message = input.readLine();
                    if (null == message || "Disconnect".contentEquals(message)) {
                        Thread.interrupted();
                        message = "Server Disconnected.";
                        showMessage(message, Color.RED);
                        break;
                    }
                    showMessage("Server: " + message, clientTextColor);
                }

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

        }

        void sendMessage(final String message) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        if (null != socket) {
                            PrintWriter out = new PrintWriter(new BufferedWriter(
                                    new OutputStreamWriter(socket.getOutputStream())),
                                    true);
                            out.println(message);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }

    }

    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

Client and server are written as two different projects, so

* You can download the complete Server source code from here.

* And the Client Source code from here

Thanks for reading. Please leave your valuable comments below.

24 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
  10. rayzox

    Hello thank you for this post … But when i try to send a message (for exemple : “hey i’m here” in clientThread.sendmessage(“hey i’m here”); ) it’s never received the message … but if i destroy the app he receive the deconnect message … it’s normal ?

    Reply
    1. James Post author

      Dear rayzox,

      Sorry for the error. I will check and reply. It was a perfectly working code.

      Thanks.

      Reply
      1. rayzox

        Hi thank you. Can you find the solution ? Because i tried x) and only the sendmessage not working :/

        Reply
      2. rayzox

        Hi ! I test and the sendmessage not working when you use it in out of the thread (for example in a click action).

        Reply
    1. James Post author

      Hi Hussain,

      Php is a server side script, if you want to call a php service you can use http calls. Or if you explicitly want a separate socket connection I suggest you to read from this documentation (http://php.net/manual/en/function.socket-create.php). Android Client part wont change other than the server IP and the PORT number.

      Thanks.

      Reply

Leave a Reply

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