Monday, January 5, 2015

File transfer via Socket, between Android devices

This example show how to transfer file between Android devices, via Socket.

In server side, it start a Thread to run a ServerSocket and wait for connection. Once connected, start another Thread to send file.

In client side, start a Thread to connect to server and download file.

In this example, the file to send and receive are fixed test.txt in external storage.



Server Side:

MainActivity.java
package com.example.androidsocketfiletransferserver;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
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.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.os.Environment;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

 TextView infoIp, infoPort;

 static final int SocketServerPORT = 8080;
 ServerSocket serverSocket;
 
 ServerSocketThread serverSocketThread;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  infoIp = (TextView) findViewById(R.id.infoip);
  infoPort = (TextView) findViewById(R.id.infoport);

  infoIp.setText(getIpAddress());
  
  serverSocketThread = new ServerSocketThread();
  serverSocketThread.start();
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();
  
  if (serverSocket != null) {
   try {
    serverSocket.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;
 }
 
 public class ServerSocketThread extends Thread {

  @Override
  public void run() {
   Socket socket = null;
   
   try {
    serverSocket = new ServerSocket(SocketServerPORT);
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      infoPort.setText("I'm waiting here: " 
       + serverSocket.getLocalPort());
     }});
    
    while (true) {
     socket = serverSocket.accept();
     FileTxThread fileTxThread = new FileTxThread(socket);
     fileTxThread.start();
    }
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } finally {
    if (socket != null) {
     try {
      socket.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
   }
  }

 }
 
 public class FileTxThread extends Thread {
  Socket socket;
  
  FileTxThread(Socket socket){
   this.socket= socket;
  }

  @Override
  public void run() {
   File file = new File(
     Environment.getExternalStorageDirectory(), 
     "test.txt");
   
   byte[] bytes = new byte[(int) file.length()];
   BufferedInputStream bis;
   try {
    bis = new BufferedInputStream(new FileInputStream(file));
    bis.read(bytes, 0, bytes.length);
    OutputStream os = socket.getOutputStream();
    os.write(bytes, 0, bytes.length);
    os.flush();
    socket.close();
    
    final String sentMsg = "File sent to: " + socket.getInetAddress();
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      Toast.makeText(MainActivity.this, 
        sentMsg, 
        Toast.LENGTH_LONG).show();
     }});
    
   } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } finally {
    try {
     socket.close();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
   
  }
 }
}

activity_main.xml
<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="com.example.androidsocketfiletransferserver.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:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="File Transfer Server"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/infoport"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textStyle="italic" />

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

</LinearLayout>

Add permission of "android.permission.INTERNET" and "android.permission.READ_EXTERNAL_STORAGE" to AndroidManifest.xml.

download filesDownload the files.


Client Side:

MainActivity.java
package com.example.androidsocketfiletransferclient;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import android.support.v7.app.ActionBarActivity;
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;
import android.os.Bundle;
import android.os.Environment;

public class MainActivity extends ActionBarActivity {

 EditText editTextAddress;
 Button buttonConnect;
 TextView textPort;

 static final int SocketServerPORT = 8080;

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

  editTextAddress = (EditText) findViewById(R.id.address);
  textPort = (TextView) findViewById(R.id.port);
  textPort.setText("port: " + SocketServerPORT);
  buttonConnect = (Button) findViewById(R.id.connect);
  
  buttonConnect.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    ClientRxThread clientRxThread = 
     new ClientRxThread(
      editTextAddress.getText().toString(), 
      SocketServerPORT);
    
    clientRxThread.start();
   }});
 }

 private class ClientRxThread extends Thread {
  String dstAddress;
  int dstPort;

  ClientRxThread(String address, int port) {
   dstAddress = address;
   dstPort = port;
  }

  @Override
  public void run() {
   Socket socket = null;
   
   try {
    socket = new Socket(dstAddress, dstPort);
    
    File file = new File(
      Environment.getExternalStorageDirectory(), 
      "test.txt");
    
    byte[] bytes = new byte[1024];
    InputStream is = socket.getInputStream();
       FileOutputStream fos = new FileOutputStream(file);
       BufferedOutputStream bos = new BufferedOutputStream(fos);
       int bytesRead = is.read(bytes, 0, bytes.length);
       bos.write(bytes, 0, bytesRead);
       bos.close();
       socket.close();
       
       MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      Toast.makeText(MainActivity.this, 
        "Finished", 
        Toast.LENGTH_LONG).show();
     }});
    
   } catch (IOException e) {

    e.printStackTrace();
    
    final String eMsg = "Something wrong: " + e.getMessage();
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      Toast.makeText(MainActivity.this, 
        eMsg, 
        Toast.LENGTH_LONG).show();
     }});
    
   } finally {
    if(socket != null){
     try {
      socket.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
   }
  }
 }

}

activity_main.xml
<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="com.example.androidsocketfiletransferclient.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:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="File Transfer Client"
        android:textStyle="bold" />

    <EditText
        android:id="@+id/address"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="dstAddress" />

    <TextView
        android:id="@+id/port"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/connect"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Connect..." />

</LinearLayout>

Add permission of "android.permission.INTERNET" and "android.permission.WRITE_EXTERNAL_STORAGE" to AndroidManifest.xml.

download filesDownload the files.


Next:
Transfer image between Android devices, via Socket

More example of Android Network programming
- Bi-directional communication between Client and Server, using ServerSocket, Socket, DataInputStream and DataOutputStream

18 comments:

  1. Sos mi idolo! q excelente tutorial

    ReplyDelete
  2. With both of your tutorials (sending image and sending file) I got the same error like this:
    Is there any fix? Thank you.

    E/DatabaseUtils﹕ Writing exception to parcel
    java.lang.SecurityException: Permission Denial: get/set setting for user asks to run as user -2 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL

    ReplyDelete
  3. hello Nguyen Vu Long,

    I also want know more about it.

    It fail in client side? or server side?

    What device/Android version you are running. What's the target SDK and min SDK you set in manifest?

    thx
    Eric

    ReplyDelete
  4. Hello, thx for your blog. It is very useful for me.
    I have a question. I want to send message via wifi, with C# client to android server.
    I use this code in your blog for android app:
    http://android-er.blogspot.com/2014/02/android-sercerclient-example-client.html

    and the c# program using 2 backgroundworker :

    https://mail.google.com/mail/u/0/?ui=2&ik=05078245dc&view=att&th=14efcbad5680fda7&attid=0.1&disp=safe&realattid=f_icyg10ow0&zw

    can you download it?
    my gmail: astro.sepehr@gmail.com
    This apps connect together but the messages does not show.

    Please help me. thx

    ReplyDelete
  5. Where do i place the test.txt file,i mean what is the path to that folder

    ReplyDelete
  6. in the root of your ExternalStorageDirectory.

    ReplyDelete
  7. Server side is always showing "Something Wrong! java.net.SocketException", what could be the reason for it?

    Thanks!

    ReplyDelete
  8. add Internet permission

    ReplyDelete
  9. if file size is more than 1kb programm don't work. how i can repair it?

    ReplyDelete
  10. i am using this code, but my application is not working properly ,after click on connect button application close unfortunately application has stopped msg displays
    and error shows in console of client side code

    E/AndroidRuntime: FATAL EXCEPTION: Thread-11553
    Process: com.example.moraya.socketfileserverside1, PID: 32027
    java.lang.ArrayIndexOutOfBoundsException: length=1024; regionStart=0; regionLength=-1
    at java.util.Arrays.checkOffsetAndCount(Arrays.java:1719)
    at java.io.BufferedOutputStream.write(BufferedOutputStream.java:135)
    at com.example.moraya.socketfileserverside1.MainActivity$ClientRxThread.run(MainActivity.java:75)
    D/OpenGLRenderer: endAllStagingAnimators on 0xb81c2c30 (RippleDrawable) with handle 0xb8211e88

    please give me solution how to solve this error.

    ReplyDelete
  11. hi sir, thank you
    my application is not working , after click on connect button shows error unfortunately application has stopped.
    please help me what is the problem in my code
    Thanks

    ReplyDelete
  12. file sent to: null msg displays on server side application and in client side code after click on connect button application shows message "Unfortunately clientSideApplication has stopped"
    please help me , what is the error and how to solve it
    Thanks in advance

    ReplyDelete
  13. Hi sir , both client side and server side application launch successfully but when performing operation(transferring file) on client side to server side then after click on connect button application terminate and in server side application message shows file sent to:null.
    please help me, how to solve this error

    ReplyDelete
  14. Thanks for such a nice and clean tutorial.

    I just want to know, If I need to send some text (not the file) how can I do that ?
    Please help !!

    ReplyDelete
  15. hello Vijay Sharma:

    please refer:
    Android Server/Client example - server side using ServerSocket(http://android-er.blogspot.com/2014/02/android-sercerclient-example-server.html)
    and client side using Socket(http://android-er.blogspot.com/2014/02/android-sercerclient-example-client.html).

    ReplyDelete
  16. Hi. Thanks it was very helpful.
    Can u help us in trying to transfer any file from the file explorer instead of 1 particular file.

    ReplyDelete
  17. This is new to me and I like the article..you really had helped me to bring into my knowledge easiest way to fix my issues

    ReplyDelete