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

48 comments:

  1. 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.

    ReplyDelete
  2. 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

    ReplyDelete
  3. 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?

    ReplyDelete
    Replies
    1. Add the permissions
      (Uses internet,access ntwk state )

      Delete
  4. 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).

    ReplyDelete
  5. 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?

    ReplyDelete
  6. 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?

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

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

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

    ReplyDelete
  10. 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.

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

    ReplyDelete
  12. 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

    ReplyDelete
  13. Hello Mallik,

    I have no idea right now.

    I think serverSocket and webSocket cannot communicate directly.

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

    ReplyDelete
  15. 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

    ReplyDelete
  16. 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

    ReplyDelete
  17. 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?

    ReplyDelete
  18. Thanks for the tutorial its quite helpful!!!!!

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

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

    ReplyDelete
  20. Hi!

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

    Regards

    ReplyDelete
  21. 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.

    ReplyDelete
  22. 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.

    ReplyDelete
  23. 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?

    ReplyDelete
  24. 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.

    ReplyDelete
  25. 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 !!

    ReplyDelete
  26. 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

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

    ReplyDelete
  28. 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.

    ReplyDelete
  29. 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.

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

    ReplyDelete
  31. hello kirti kumar,

    The post already had links to download the code.

    ReplyDelete
  32. 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

    ReplyDelete
  33. 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.

    ReplyDelete
  34. 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?

    ReplyDelete
  35. 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.

    ReplyDelete
  36. This comment has been removed by the author.

    ReplyDelete
  37. 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?

    ReplyDelete
  38. 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.

    ReplyDelete
  39. 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

    ReplyDelete
  40. 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

    ReplyDelete
  41. Hi sir,
    Can you please tell me 1 thing.
    When the connection is established how to show another page for few sec.
    I am creating a game app so when the connection is established is should go to the game page play for 2 min and then return the score.
    Can we implement it using this??

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

    ReplyDelete
  43. how to pass music files through socket

    ReplyDelete