Sunday, June 15, 2014

Android TCP/IP client-server socket program (part two)

This is the second part of the post. In this part I will describe the implementation of the TCP/IP Android client program. I tested these two programs by connecting two Android devices over a Wi-Fi network. The deice which host the Wi-Fi hotspot has the server program. Then I connected another Android device which has the client program to that Wi-Fi hotspot. If you want to create the server program first check this post.
Client program has one Activity and one layout. You can download the complete client program from here.

Demo of the client application.
Here is the code for client main activity : 

package com.codeoncloud.androidclient;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import android.support.v7.app.ActionBarActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {
 private TextView tvServerMessage;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  tvServerMessage = (TextView) findViewById(R.id.textViewServerMessage);
  //Create an instance of AsyncTask
  ClientAsyncTask clientAST = new ClientAsyncTask();
  //Pass the server ip, port and client message to the AsyncTask
  clientAST.execute(new String[] { "192.168.1.1", "8080","Hello from client" });
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  int id = item.getItemId();
  if (id == R.id.action_settings) {
   return true;
  }
  return super.onOptionsItemSelected(item);
 }
/**
 * AsyncTask which handles the communication with the server 
 */
 class ClientAsyncTask extends AsyncTask<String, Void, String> {
  @Override
  protected String doInBackground(String... params) {
   String result = null;
   try {
    //Create a client socket and define internet address and the port of the server
    Socket socket = new Socket(params[0],
      Integer.parseInt(params[1]));
    //Get the input stream of the client socket
    InputStream is = socket.getInputStream();
    //Get the output stream of the client socket
    PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
    //Write data to the output stream of the client socket
    out.println(params[2]); 
    //Buffer the data coming from the input stream
    BufferedReader br = new BufferedReader(
      new InputStreamReader(is));
    //Read data in the input buffer
    result = br.readLine();
    //Close the client socket
    socket.close();
   } catch (NumberFormatException e) {
    e.printStackTrace();
   } catch (UnknownHostException e) {
    e.printStackTrace();
   } catch (IOException e) {
    e.printStackTrace();
   }
   return result;
  }
  @Override
  protected void onPostExecute(String s) {
   //Write server message to the text view
   tvServerMessage.setText(s);
  }
 }
}

This activity will involve in three main functions.
1.    Make a request to connect to the server.
2.    Read the input data stream coming from the server.
3.    Send data to the server.

Unlike the server program in the client program all these three tasks will be done by one AsyncTask, here named as ClientAsyncTask. An instance of the AsyncTask will be created and execution of the AsyncTask will be started in the main UI thread of the program [line 26, 28]. The internet address, the port number of and the client message pass as String parameters to the AsyncTask [line 28]. Check with your server application and change the ip address and port.

1.Make a request to connect to the server.
In the AsyncTask first client socket will be created by giving the server ip and port [line 53]. This will make a reaquest to the given server program over the Wi-Fi network since here I connected two devices using Wi-Fi hotspot.

2.Read the input data stream coming from the server.
Input stream of the client socket will be captured [line 57]. Data coming as the stream will be store in a buffer [line 63]. Data in the incoming buffer will be read line by line [line 66] and return the resulting string [line 76].

3.Send data to the server.
This is done using a Printwriter object. First data output stream of the client socket will be captured in to a Printwriter object [line 59]. Then the client message will write in to the print writer [line 61].

After completing client communication the client socket will be closed [line 68]. Then onPostExecute method of the AsyncTask will be executed and the server message will be write in to the text view [line 81].

Here is the code for main activity layout  :

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.codeoncloud.androidclient.MainActivity"
    tools:ignore="MergeRootFrame" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="25dp"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/textViewsrvrMsg"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="Server msg"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=":"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <TextView
            android:id="@+id/textViewServerMessage"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium" />
    </LinearLayout>

</FrameLayout>

To perform network related functions we have to grant few permissions from Manifest file.
i.e.
 <uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
The manifest file after adding all the permissions.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.codeoncloud.androidclient"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.codeoncloud.androidclient.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

I have tested the server and client program on two Android devices connected via a Wi-Fi network. When you are testing first run the server application and then run the client application.These two applications has only the essential functionalists to complete a TCP/IP client server communication using plain java sockets. You can add your own functions to improve this program.

Happy coding  :)

3 comments:

  1. Also - you need to get yourself up the search ratings. They are dominated by out of date solutions! Keith H.

    ReplyDelete
  2. what if I want multiple clients to connect to server and than server listen to clients one by one or in parallel??

    ReplyDelete
  3. when we create a hotspot on server along with cellular data the client wont receive the message..what is the cause for that.is there a way we can communicate from a socket via wifi and communicate with the internet at the same time ?

    ReplyDelete