Wednesday, August 6, 2014

Bi-directional communication between Client and Server, using ServerSocket, Socket, DataInputStream and DataOutputStream

This example show bi-directional communication between Client and Server, both run on Android devices.

  • When the Server run, it will show it's own IP and port, open a ServerSocket and wait for socket connection from clients. 
  • In Client side, enter message to be sent to server, enter the server Ip and port, then clieck Connect... button, The client will connect to server using socket with DataInputStream and DataOutputStream loaded with message to send. 
  • In client side, when serverSocket.accept(), it will retrieve the message sent with dataInputStream.readUTF().
Both client and server need permission of "android.permission.INTERNET" in AndroidManifest.xml.

Notice:
- All code for network operation should run in background thread.
- The code dataInputStream.readUTF() will block the program flow if no data input. (Read Pervent program blocked by DataInputStream.readUTF())


Example code in Server Side:
package com.example.androidserversocket;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;

import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView;

public class MainActivity extends Activity {

 TextView info, infoip, msg;
 String message = "";
 ServerSocket serverSocket;

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

  infoip.setText(getIpAddress());

  Thread socketServerThread = new Thread(new SocketServerThread());
  socketServerThread.start();
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();

  if (serverSocket != null) {
   try {
    serverSocket.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }

 private class SocketServerThread extends Thread {

  static final int SocketServerPORT = 8080;
  int count = 0;

  @Override
  public void run() {
   Socket socket = null;
   DataInputStream dataInputStream = null;
   DataOutputStream dataOutputStream = null;

   try {
    serverSocket = new ServerSocket(SocketServerPORT);
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      info.setText("I'm waiting here: "
        + serverSocket.getLocalPort());
     }
    });

    while (true) {
     socket = serverSocket.accept();
     dataInputStream = new DataInputStream(
       socket.getInputStream());
     dataOutputStream = new DataOutputStream(
       socket.getOutputStream());

     String messageFromClient = "";
     
     //If no message sent from client, this code will block the program
     messageFromClient = dataInputStream.readUTF();
     
     count++;
     message += "#" + count + " from " + socket.getInetAddress()
       + ":" + socket.getPort() + "\n"
       + "Msg from client: " + messageFromClient + "\n";

     MainActivity.this.runOnUiThread(new Runnable() {

      @Override
      public void run() {
       msg.setText(message);
      }
     });

     String msgReply = "Hello from Android, you are #" + count;
     dataOutputStream.writeUTF(msgReply);

    }
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    final String errMsg = e.toString();
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      msg.setText(errMsg);
     }
    });
    
   } finally {
    if (socket != null) {
     try {
      socket.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }

    if (dataInputStream != null) {
     try {
      dataInputStream.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }

    if (dataOutputStream != null) {
     try {
      dataOutputStream.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
   }
  }

 }

 private String getIpAddress() {
  String ip = "";
  try {
   Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
     .getNetworkInterfaces();
   while (enumNetworkInterfaces.hasMoreElements()) {
    NetworkInterface networkInterface = enumNetworkInterfaces
      .nextElement();
    Enumeration<InetAddress> enumInetAddress = networkInterface
      .getInetAddresses();
    while (enumInetAddress.hasMoreElements()) {
     InetAddress inetAddress = enumInetAddress.nextElement();

     if (inetAddress.isSiteLocalAddress()) {
      ip += "SiteLocalAddress: "
        + inetAddress.getHostAddress() + "\n";
     }

    }

   }

  } catch (SocketException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   ip += "Something Wrong! " + e.toString() + "\n";
  }

  return ip;
 }
}

Layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    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=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/infoip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

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

        <TextView
            android:id="@+id/msg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </ScrollView>

</LinearLayout>


download filesDownload the files.


Example code in Client Side:
package com.example.androidclient;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

 TextView textResponse;
 EditText editTextAddress, editTextPort;
 Button buttonConnect, buttonClear;
 
 EditText welcomeMsg;

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

  editTextAddress = (EditText) findViewById(R.id.address);
  editTextPort = (EditText) findViewById(R.id.port);
  buttonConnect = (Button) findViewById(R.id.connect);
  buttonClear = (Button) findViewById(R.id.clear);
  textResponse = (TextView) findViewById(R.id.response);
  
  welcomeMsg = (EditText)findViewById(R.id.welcomemsg);

  buttonConnect.setOnClickListener(buttonConnectOnClickListener);

  buttonClear.setOnClickListener(new OnClickListener() {

   @Override
   public void onClick(View v) {
    textResponse.setText("");
   }
  });
 }

 OnClickListener buttonConnectOnClickListener = new OnClickListener() {

  @Override
  public void onClick(View arg0) {
   
   String tMsg = welcomeMsg.getText().toString();
   if(tMsg.equals("")){
    tMsg = null;
    Toast.makeText(MainActivity.this, "No Welcome Msg sent", Toast.LENGTH_SHORT).show();
   }
   
   MyClientTask myClientTask = new MyClientTask(editTextAddress
     .getText().toString(), Integer.parseInt(editTextPort
     .getText().toString()),
     tMsg);
   myClientTask.execute();
  }
 };

 public class MyClientTask extends AsyncTask<Void, Void, Void> {

  String dstAddress;
  int dstPort;
  String response = "";
  String msgToServer;

  MyClientTask(String addr, int port, String msgTo) {
   dstAddress = addr;
   dstPort = port;
   msgToServer = msgTo;
  }

  @Override
  protected Void doInBackground(Void... arg0) {

   Socket socket = null;
   DataOutputStream dataOutputStream = null;
   DataInputStream dataInputStream = null;

   try {
    socket = new Socket(dstAddress, dstPort);
    dataOutputStream = new DataOutputStream(
      socket.getOutputStream());
    dataInputStream = new DataInputStream(socket.getInputStream());
    
    if(msgToServer != null){
     dataOutputStream.writeUTF(msgToServer);
    }
    
    response = dataInputStream.readUTF();

   } catch (UnknownHostException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    response = "UnknownHostException: " + e.toString();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    response = "IOException: " + e.toString();
   } finally {
    if (socket != null) {
     try {
      socket.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }

    if (dataOutputStream != null) {
     try {
      dataOutputStream.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }

    if (dataInputStream != null) {
     try {
      dataInputStream.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
   }
   return null;
  }

  @Override
  protected void onPostExecute(Void result) {
   textResponse.setText(response);
   super.onPostExecute(result);
  }

 }

}

Layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <EditText 
        android:id="@+id/welcomemsg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Say hello to server" />
    <EditText 
        android:id="@+id/address"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="dstAddress" />
    <EditText 
        android:id="@+id/port"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="dstPort" />
    <Button 
        android:id="@+id/connect"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Connect..."/>
    <Button 
        android:id="@+id/clear"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Clear"/>
    <TextView
        android:id="@+id/response"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>


download filesDownload the files.


Client and Server run on WiFi share hotspot:

The following video, at 1:22, show it work when both client and server connect to the shared WiFi network from server hotspot.



Next:
Pervent program blocked by DataInputStream.readUTF()
Editable message sent from server
Java/JavaFX Client link to Android Server
Java/JavaFX Client run on Raspberry Pi, link with Android Server
Java/JavaFX Server link to Android Client
- A Simple Chat App

47 comments:

blackjwl said...

This is awesome. I love how simple it is. I have two questions however:

if I want to send messages from the server to the client as well and have the server receive them would it work if I use the client side of your code into the server part of the code and the server part of your code into the client side of the code?

Also I am thinking of changing it so that when pressing connect a new screen shows up where the client can also view the chat messages from the server and send messages. Will it be possible to do this through intents? Sorry if my questions sound silly. I am new to android programming.

Erik said...

hello blackjwl,

"send messages from the server to the client" have already been done in the example. The message "Hello from Android, you are #" is sent from server to client after connected.

For "chat" application, I have no idea right now, may be will try later.

Thx

blackjwl said...

I see, well I am working on that these days and your code seemed pretty much the solution to a chat application as I thought I only need to add a text box to the server app's xml layout and enter text instead of sending a hard coded message. I did not mean a fully fledged chat application only chatting between the server and client taking place in the simplest way possible.

Anyway I have tried to run your code on two separate emulators and I do not get the local IP address shown as the "SiteLocalAddress" when I run the server app. I only see one SiteLocalAddress statement mentioning "10.0.2.15"
and when I enter that into the client app on the other emulator I got an IOexception java.net.ConnectException saying failed to connect to 10.0.2.15. Connect failed ECONNREFUSED(connection refused).

After that when I entered my computer's local IP address into the client app's text box thinking maybe it would work even if it doesn't show it but absolutely NOTHING happened. I had copied and pasted your code exactly as it is and had run it. Any idea why I can;t run it like you did in the video?

blackjwl said...

I forgot to mention one other thing, when I tried to run the apps again on the two separate emulators, and I put in the local ip address of my computer even though it did not show up on the server app, I decided to wait and see what happens and I ended up getting an error saying failed to connect to 192.168.0.7 ETIMEDOUT(Connection timed out).

blackjwl said...

if I run the server app on the mobile and the client app on the emulator your code works however. I am still trying to make the server send a message from the user to the client through a textbox rather than a hardcoded string message but the application just crashes. I have been at this all day and it is starting to drive me crazy.

ServerActivity.this.runOnUiThread(new Runnable() {

@Override
public void run() {
msg.setText(message);

}
});

sendChat.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {

chatMsg= chatBoxText.getText().toString();
try {
dataOutputStream.writeUTF(chatMsg);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

});

Any clues on how I can insert a textfield that would send the message to the client without causing it to crash?

Erik said...

hello blackjwl,

Is it http://android-er.blogspot.com/2014/08/clientserver-example-editable-message.html what you want?

Strongly recommend NOT to test on Emulator.

Unknown said...

Thank you so much. :) this tutorial proved to be very useful! :)

But, I'm working on a project in were I need to broadcast a message from the server (for say)to multiple clients connected in the same network. Or any of of the clients to other clients and the server. Actually I'm building a Wi-Fi group chat. Can you please help me in this?

Erik said...

Please check:

Implement simple Android Chat Application, server side..

and

Simple Android Chat Application, client side.

Sabri said...

Is it gonna work if I try to connect on different networks?

Unknown said...

Awesome....It is really working.Can you please provide a similar code which can transfer files between two android devices

Erik said...

hello Sauradipta Mishra,

Please check File transfer via Socket, between Android devices.

Anonymous said...

Hi guys,
Could anyone give me a Python socket server code (I have a server running Python). Thanks a lot.

Anonymous said...

Thanx for sharing such code. it's really good example.

But, I have one question. Can we make server devices ip adr. static? with code or with android user interface? We may get rid of entering Ip adr. and port every time.

Erik said...

sure you can make the ip static. But it is not the job in the application.

Mallik said...

Hello,

I need to communicate between android code and JavaScript code(webView) of same application.
My implementation is as follows,
1. Created serverSocket connection in android as described in your example code. Start this server in onCreate of Activity.
2. Created webSocket connection in JavaScript code.

Result:
I am able see some messages being read in serverSocket read() method. Data is related websocket creation details
(http header, connection upgraded to socket, user agent, etc).
I tried sending http handshake message from serverSocket(Android code) to websocket(JavaScript code).
WebSocket in JavaScript received onopen() callback function but it immidaitely recived onclose() callback with reason code 1006.


Note: ServerSocket is listening to port 8080.
Websocket is cerated using URL - "wb:127.0.0.1:8080"

Please let me know if my approach is wrong.

Is it possible to communicate between serverSocket and webSocket?
Or is there any other way to create WebSocket Server in andorid similar to serverSocket and communicate with JavaScript websocket?

Mallikarjun

Erik said...

Hello Mallik,

I have no idea right now.

I think serverSocket and webSocket cannot communicate directly.

Unknown said...

Please,,,,,I need a way to made two mobiles to be connected. Via WIFI and playTicTacToe on them

Tech said...

my android mobile is client only, my wifi module is server , if i connect from client the server should connect and the server sending should be seen in a label. for this how to edit your code. please guide

salma said...

hi
i use eclipse with target 17 and i use 2 emulator android on eclipse when i run the application i have a prbm in client i can't connect to the server i have an exception (connection refused)plz hel me

Anonymous said...

Hello,,,im just thinking if it is possible to divide the codes on connect button. by creating 2 buttons[connect,send].connect is just simply notify you if its connected, then send is to send a message to the server. can anyone help me?

Anonymous said...

Add the permissions
(Uses internet,access ntwk state )

Unknown said...

Thanks for the tutorial its quite helpful!!!!!

How can I send the location of the server to client on button click.

Anonymous said...

As expected, Always find a solution from your blog.Thank you

Andr.engineer said...

Hi!

is posible to use the same code for ObjectInputStream and ObjectInputStream? Because, i tried but i didnt have any result. Thanks!!

Regards

Unknown said...

Hi,

I am trying to execute your example, but i always got failed to connect IOException also isConnectedFailed: EHOSTUNREACH(no route to host), Please help to resolve this exception.

Unknown said...

I am trying to execute your example, but i always got failed to connect IOException also isConnectedFailed: EHOSTUNREACH(no route to host), Please help to resolve this exception.

Unknown said...

Hi
Thank you so much for your shared code. It is very useful.
I have question. imagine we have many clients. can server send message to specific client ?
for example We have 192.168.43.228 and 192.168.43.154 as client . can server send message to just 192.168.43.228?

Erik said...

Hello Rasoul Gholamhosseinzadeh,

In this example, the server start ServerSocket and wait request from client. The communication link is initiate by client, then server reply something, than close. So the server cannot initiate communication to client.

But you can check socket.getInetAddress() to determine what to reply.

Unknown said...

I only implemented client code since I need to connect to a telnet server.
Is this possibile ??
When I press connect I obtain no messages and no errors. Simply, nothing happens !!

Unknown said...

i have a same question:
Rasoul Gholamhosseinzadeh said...
Hi
Thank you so much for your shared code. It is very useful.
I have question. imagine we have many clients. can server send message to specific client ?
for example We have 192.168.43.228 and 192.168.43.154 as client . can server send message to just 192.168.43.228?
anybody have example?help please

Erik said...

Hello Rasoul Gholamhosseinzadeh and Iqra Ali,

I think what you want is Android Chat example, with server sending individual message to specify client..

Unknown said...

thankyou :)
its really helpful
and if i want to communicate with different network. any example about this?

Unknown said...

i want to communicate with different network. any example about this?
and also i want some modification like a client sends a msg to the server then server forward it to other user.

Unknown said...

hey thank you for code. i used your client side code and use another app as server i can send a msg but i can not receive from another server app and also cant see the chat panel which is shown in ur video.

Unknown said...

Hello I want server and client side code is it possible to give me this code my emaild id is kirtigiripunje@gmail.com thanks

Erik said...

hello kirti kumar,

The post already had links to download the code.

Anonymous said...

Hello,
On the Client side, I would like to connect to the server, then send multiple messages. At the moment, I am able to connect once and send a message, however, when I click on the "Connect" button again it tries to create a new socket. I want the same connected socket to send multiple messages. Is it possible? Is there another example with this implementation?
Thanks

neo said...

i want to run this client and server in different network and want them to communicate. how do i do this. how to do port forwarding.

Unknown said...

on my router wifi its work,phones are connect, when the ip is 10.0.0.2, but in mobile network how can it work? what need to change?

Erik said...

hello Pavel Palei,

As I know, most mobile network provider block your port as server, not related to the program. So mobile phone can be a client, but not as server.

Unknown said...
This comment has been removed by the author.
Unknown said...

why we need to create new Socket every time we send massage? the connection stop after thread executed?
is there another ways communicate with sockets?

Erik said...

hello Pavel Palei,

Depends on your implementation. In this simple example, client side only connect to server, send data, and close.

Refer to another example of A Simple Chat App (listed below "Next:"), connection no close after connected.

Unknown said...

i have problem i dont recived data i recevd java.io.EOFException
NB:i have a python client and i send the data it is tested

Anonymous said...

Hi sir,Thank you very much very good tutorial.
But sir , I have one question how to transfer file or bidirectional communication "file" using socket ..please help me .thanks

Unknown said...

Sir, how to transfer live camera preview from mobile to mobile using socket

Anonymous said...

how to pass music files through socket