Sockets, sent pdf file always arrives zero bytes size

I'm sending a pdf file from android tablet client to Java app running on Windows 7. The file always arrives as a size of zero bytes. what is the problem here?

Before the pdf file was sent from client to server, the size of the file as long value is sent from client to server, this size is correct and always arrives to the server. For the pdf file, I'm using for this test the size is 566718 bytes.

How can I get the pdf file to arrive as the correct size?

Server code

 public class Server {
 ServerSocket serverSocket;
 Socket socket;
 boolean runner = true;

Server() throws IOException{

    serverRunner();
    System.out.println("server constructor started");

} // Server() constructor

public void serverRunner() throws IOException {

    System.out.println("serverrunner started");

     try {

      serverSocket = new ServerSocket(6789, 100);

      runner = true;

        while (runner) {

            socket = serverSocket.accept();

            MultiThreader multi = new MultiThreader(socket);
            Thread t = new Thread(multi);
            t.start();

        }  // while runner
       } catch (IOException ex) {

    }

 } // serverRunner()

 } // class Server


public class MultiThreader implements Runnable {
Socket socket;
public int fileSizeFromClient;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
DataInputStream dis = null;
DataOutputStream dos = null;

public MultiThreader(Socket socket){
    System.out.println("print out from multithreader class");
    this.socket = socket;

} // multiThreader

@Override
public void run() {

    System.out.println("multi threader started");

    // action #1 read file from client =====================================
    // transfer.pdf read this file sent from android device to this computer

    int bufferSize = 0;

    try {

     bis = new BufferedInputStream(socket.getInputStream());
     dis = new DataInputStream(bis);

     fileSizeFromClient = dis.readInt();
     System.out.println("file size from client is " + fileSizeFromClient);

      File fileDirectory = new File("C:/DOWNLOAD/");
        if (!fileDirectory.exists()) {
            fileDirectory.mkdir();
      }
      File file = new File("C:/DOWNLOAD/transfer.pdf");
      file.createNewFile();

       fos = new FileOutputStream(file);
       bos = new BufferedOutputStream(fos);
       dos = new DataOutputStream(bos);

       byte[] buffer = new byte[fileSizeFromClient];

      int totalBytesRead = 0;

        while(totalBytesRead < fileSizeFromClient){
            int bytesRemaining = fileSizeFromClient = totalBytesRead;
            int bytesRead = dis.read(buffer, 0, (int) Math.min(buffer.length, bytesRemaining));
            if(bytesRead == -1) {
                break;
            } else {
                dos.write(buffer, 0, bytesRead); 
                    totalBytesRead += bytesRead;
            }
        } // while

      } catch (IOException ex) {
        Logger.getLogger(MultiThreader.class.getName()).log(Level.SEVERE, null, ex);
      } finally {
        try {
          //  socket.close();
        } catch (IOException ex) {
            Logger.getLogger(MultiThreader.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

} // run

} // MultiThreader

client code

 public class MainActivity extends Activity implements Runnable {

TextView textViewOne;
Button buttonOne;
Socket socket;
private String serverIP = "192.XXX.X.X";
FileInputStream fis;
FileOutputStream fos;
private File file;
DataInputStream dis;
DataOutputStream dos;
BufferedInputStream bis;
BufferedOutputStream bos;
long length;

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

   textViewOne = (TextView) findViewById(R.id.textView1);
   buttonOne = (Button) findViewById(R.id.button1);

   buttonOne.setOnClickListener(new OnClickListener() {

    @Override
    public void onClick(View v) {
        Thread myThread = new Thread(MainActivity.this);
        myThread.start();

    }

   });

} // oncreate

@Override
public void run() {

    MainActivity.this.runOnUiThread(new Runnable(){
        @Override
        public void run() {
           textViewOne.setText("run method started");
        }
        });

    try {
        socket = new Socket(InetAddress.getByName(serverIP), 6789);

        if (socket == null) {
            return;
        } else {
            MainActivity.this.runOnUiThread(new Runnable(){
                @Override
                public void run() {
                   textViewOne.setText("connected");
                }
                });

        }

        file = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + "transfer.pdf");

        length = file.length();

        fis = new FileInputStream(file);
        bis = new BufferedInputStream(fis);
        dis = new DataInputStream(bis);

        bos = new BufferedOutputStream(socket.getOutputStream());
        dos = new DataOutputStream(bos);

        dos.writeInt((int) length); // sends the length as number bytes is file size

        int count = 0;
        byte[] buffer = new byte[(int) length];

        while ((count = bis.read(buffer)) > 0)
        {
            bos.write(buffer, 0, count);
        }

        bos.flush();
        bis.close();
        socket.close();

    } catch (UnknownHostException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

 } // mainactivity
Jon Skeet
people
quotationmark

This is the problem, I believe.

int bytesRemaining = fileSizeFromClient = totalBytesRead;

That's doing two assignments, so you're assigning 0 to fileSizeFromClient immediately, and exiting the loop.

You meant:

int bytesRemaining = fileSizeFromClient - totalBytesRead;

That's a pretty subtle typo, and you were unlucky that it's a typo which still resulted in valid code :(

Given that you're closing the socket immediately anyway though, it's not clear why you're sending the file size first. Your code could be simpler if you just had the same "copy from an input stream to an output stream until the input runs out of data" at both the client and the server, just from a FileInputStream to a Socket's OutputStream at the client, and the Socket's InputStream to a FileOutputStream (possibly with a buffering wrapper) at the server.

I'd also recommend closing all streams - if you're using Java 7, you can do this simply using a try-with-resources statement; in earlier versions you should close streams in finally blocks.

people

See more on this question at Stackoverflow