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

16 comments:

Anonymous said...

Sos mi idolo! q excelente tutorial

Nguyen Vu Long said...

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

Andr.oid Eric said...

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

skytoday said...

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

Anonymous said...

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

Andr.oid Eric said...

in the root of your ExternalStorageDirectory.

Praveen Kumar said...

is this using the wifi p2p.??

Emrah anıl said...

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

Thanks!

Dan said...

add Internet permission

Семен Касаткин said...

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

Manoj Gayakwad said...

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.

Manoj Gayakwad said...

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

Manoj Gayakwad said...

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

Manoj Gayakwad said...

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

Vijay Sharma said...

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 !!

Andr.oid Eric said...

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