0

I'm developing an application and I want to transfer files from a computer to a phone using sockets. I'm able to transfer one file but when I want to transfer multiple files, they pile up. Here's how the program works:

  1. I get a screenshot from computer using Robot.
  2. I save it as Send.jpg.
  3. I send the image. Let's say for example its size is 1 MB.
  4. I receive the image on phone.
  5. I display it in an ImageView.
  6. And loop through these steps again until the user closes the activity on phone.

But the result is this :

I get the first screenshot (Send.jpg: 1 MB) send it and receive it on phone. Get the second one (Send.jpg: 2 MB) send it and receive it on phone. and the third one and etc...

It never gets displayed on phone. And when I check the phone storage using explorer, I see one image - its size is the size of the first image + the second + the third ...

I guess my problem is i have to stop the InputStream, please help.

Code :

Server :

package application;

import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
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.io.PrintStream;
import java.net.Socket;

import javax.imageio.ImageIO;

public class ScreenCapture {

    Socket socket;
    OutputStream os;
    Robot robot;
    PrintStream ps;

    public ScreenCapture() throws IOException, AWTException {
        // TODO Auto-generated constructor stub
        socket = SocketWrapper.getSocket();
        os = socket.getOutputStream();
        robot = new Robot();
        ps = new PrintStream(socket.getOutputStream());
        new Record().start();

    }

    private class Record extends Thread{
        @Override
        public void run() {
            while(true){
                int count;
                Rectangle rect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
                BufferedImage img = robot.createScreenCapture(rect);

                try {
                    ImageIO.write(img, "jpg", new File("/Users/Tomahawk/Documents/MovieMaker/send.jpg"));
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                FileInputStream fis;
                try {
                    File f = new File("/Users/Tomahawk/Documents/MovieMaker/send.jpg");
                    fis = new FileInputStream(f);
                    BufferedInputStream bis = new BufferedInputStream(fis);
                    byte[] byteArray = new byte[(int) f.length()];
                    long filesize = f.length();
                    while((count = bis.read(byteArray)) > 0){
                        os.write(byteArray,0,count);
                    }
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                System.out.println("Sent File");
            }
        }
    }

}

Client (Phone) :

package com.pcontrol.tomahawk.pcontrol;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.Toast;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class ScreenCapture extends Activity {

    Socket socket;
    InputStream is;
    OutputStream os;
    Scanner scanner;
    ImageView screenCap;
    long filesize = 0;
    int i=0;

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

        socket = SocketWrapper.getSocket();
        try {
            is = socket.getInputStream();
            scanner = new Scanner(is);
        } catch (IOException e) {
            e.printStackTrace();
        }

        screenCap = (ImageView) findViewById(R.id.screenCap);

        new ReceiveFiles().execute();

    }

    private class ReceiveFiles extends AsyncTask<Void,Void,Void> {
        @Override
        protected Void doInBackground(Void... params) {

            try {
                os = new FileOutputStream("/sdcard/"+i+".jpg");
                copy(is, os);
                publishProgress();
            } catch (IOException e) {
                e.printStackTrace();
            }
            i++;
            return null;
        }
        @Override
        protected void onProgressUpdate(Void... values) {
            Bitmap bmp = BitmapFactory.decodeFile("/sdcard/"+i+".jpg");
            screenCap.setImageBitmap(bmp);
        }
    }

    static void copy(InputStream in, OutputStream out) throws IOException {
        byte[] buf = new byte[60000];
        int len = 0;
        while ((len = in.read(buf)) != -1) {
            out.write(buf, 0, len);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_screen_capture, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}
adelphus
  • 10,116
  • 5
  • 36
  • 46
Tomahawk
  • 78
  • 11

1 Answers1

0

You're not telling the receiver where one file ends and the next one starts.

You could add a basic framing protocol, for example one where you first send the size of the file and then the data. That way the receiver can count the bytes it reads and knows when to close the current file and open another.

Alternatively you could use separate sockets to send each file, but it looks like that would require major changes to your architecture.

Joni
  • 108,737
  • 14
  • 143
  • 193
  • Might also be helpful to put a mutex on the file transfer methods (I.e. synchronize on an object) to avoid files content getting mixed up? As multiple AsyncTask can run simultaneously in some versions of android? I confess I am more Java than Android developer so forgive me if there is some other protection against this... – drrob Aug 16 '15 at 00:06
  • If the socket is used by more than one thread you definitely need protection. It would be even better to design the solution in a way that avoid this error completely, and not allow the socket to be shared by different threads. – Joni Aug 16 '15 at 14:36