0

I'm trying to send a file through Java sockets from one program to the other. My code is based off of this question. The issue is that on the Ubuntu machine hosting the server, the file sent over is 0 bytes in size. The code has worked on a local connection on my Windows laptop, so perhaps the issue has to do with the remote connection?

Server code:

int g = Integer.parseInt(in.readLine());
if(g > -1) {
    InputStream fIn = client.getInputStream();
    for(int i = 0; i < g; i++) {
        String name = in.readLine();
        byte[] bytes = new byte[16*1024];
        File f = new File("plugins/" + name + ".jar");
        if(!f.exists()) f.createNewFile();
        FileOutputStream fOut = new FileOutputStream(f);
        int count;
        while ((count = fIn.read(bytes)) >= 0) {
            fOut.write(bytes, 0, count);
        }
        fOut.flush();
        fOut.close();
    }
    System.out.println("[" + client.getRemoteSocketAddress().toString() + "] added " + g + " new plugins.");
    client.close();
}else{
    client.close();
}

Client code:

JFileChooser fd = new JFileChooser("C:\\");                         
fd.setFileSelectionMode(JFileChooser.FILES_ONLY);
fd.setMultiSelectionEnabled(true);
fd.setFileFilter(new FileNameExtensionFilter(null,"jar"));
int r = fd.showOpenDialog(null);
if(r == JFileChooser.APPROVE_OPTION) {
    File[] files = fd.getSelectedFiles();
    OutputStream fOut = sock.getOutputStream();
    out.println(files.length);
    for(File f : files) {
        out.println(f.getName().split("\\.")[0]);
        byte[] bytes = new byte[16 * 1024];
        FileInputStream fIn = new FileInputStream(f);
        int count;
        while ((count = fIn.read(bytes)) >= 0) {
            fOut.write(bytes, 0, count);
        }
        fIn.close();
    }
}else{
    out.println(-1);
}
sock.close();

0 bytes

Max K
  • 656
  • 1
  • 6
  • 22
  • What kind of Object is `client`? The first element / line is the number of files. Add the part the reads the number of files? There are different issues in your code: There is no delimiter in your stream that tells the server that all bytes of a file have been read and that a new file begins. Your Exception / Resource Handling. You may not close all your streams in the case of an exception which may become a real big issue on the server side. – andih Jun 08 '17 at 15:09
  • @andih client is a Socket. For each new client connected to the server, the socket is passed to a thread, so the "Server" code is nested inside run(). Yes, the first line reads the number of files, see edits. – Max K Jun 08 '17 at 15:14
  • @andih Perhaps you could post an answer adding the delimeter? Also, I handle the exceptions outside of the given code. How could my exception handling become a "real big issue" on the server side? Upon finishing the protocol, both sides terminate the connection. If there is an error thrown server side upon closing the client socket, the thread ends. Basically, if there seems to be an issue, then both sides will terminate. – Max K Jun 08 '17 at 15:19
  • The `exists()/createNewFile()` part is a complete waste of time and space. `new FileOutputStream()` then has to delete that file and create a new one anyway. Don't write pointless code. Three system calls where one would do. – user207421 Jun 09 '17 at 05:32
  • @EJP I don't see why this is a exact duplicate. Sending multiple files via socket is one aspect of the problem. There are different tutorials / example on the net how to send multiple files via socket. The "main" question was why the file size on the server side is 0 bytes. – andih Jun 09 '17 at 05:59
  • @andh It is an exact duplicate because the code in my answer there solves the problem completely whether for one file or a zillion. – user207421 Jun 09 '17 at 23:17

1 Answers1

0

As said in the comments there are different issues in you code.

To recognise the end of single file you can simply add the file size after the filename separated by a Semicolon;

out.println(f.getName().split("\\.")[0] + "; size" + f.length());

On the Server side you accumulate the file size read / written stop read ing the content of the file close it and read the next line (filename / file size).

As said in the comments there are different issues. You use fIn and fOut which is not clear how they are defined. On the client side you use fOut while the Socket OutputStream is named 'out'. Similar thing on the server side. You read the number of files from in but afterwards you get the InputStream (again?) from the Socket and use that as fIn. Depending on your in that may or may not work.

Also reading a line from via readLine from an InputStream and also binary content is not that trivial. In my example code I'm using the DataInputStream for that even the readLine method is deprecated.

The Example also uses the "try with resources" Syntax to ensure that all resources (Streams, Sockets) get closed in the case of an Exception.

The Example does not show how to deal with the file size on the server side That's up to you.

The example is completely runnable on a single machine and shows how to copy a single file via socket based on your code.

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class ClientServerSocketExample {

    private static class Server {

        public void run() throws IOException {

            try (ServerSocket serverSocket = new ServerSocket(41000, 10, InetAddress.getLocalHost())) {
                try (Socket client = serverSocket.accept()) {

                    try (DataInputStream in = new DataInputStream(client.getInputStream())) {

                        int g = Integer.parseInt(in.readLine());

                        if(g > -1) {
                            for(int i = 0; i < g; i++) {
                                String[] filenameAndSize = in.readLine().split(";");
                                String name = filenameAndSize[0];
                                byte[] bytes = new byte[16*1024];
                                File f = new File("/tmp/" + name + ".jar");
                                if(!f.exists()) f.createNewFile();
                                try (FileOutputStream fOut = new FileOutputStream(f)) {
                                    int count;
                                    while ((count = in.read(bytes)) >= 0) {
                                        fOut.write(bytes, 0, count);
                                    }
                                    fOut.flush();
                                }
                            }
                            System.out.println("[" + client.getRemoteSocketAddress().toString() + "] added " + g + " new plugins.");


                        }
                    }
                }
            }
        }

    }

    private static class Client {

        public void run() throws IOException {
            try (Socket socket = new Socket()) {
                socket.connect(new InetSocketAddress(InetAddress.getLocalHost(), 41000) );

                sendFiles(socket);
            }
        }

        private static void sendFiles(Socket sock) throws IOException {
            File[] files = new File[]{new File("some.jar")}; 
            OutputStream fOut = sock.getOutputStream();
            PrintStream out = new PrintStream(fOut);

            out.println(files.length);
            for(File f : files) {
                out.println(f.getName().split("\\.")[0] + "; size" + f.length());

                byte[] bytes = new byte[16 * 1024];
                try (FileInputStream fIn = new FileInputStream(f)) {
                    int count;
                    while ((count = fIn.read(bytes)) >= 0) {
                        out.write(bytes, 0, count);
                    }
                    out.flush();
                }
            }
        }


    }



    public static void main(String ... args) throws IOException, InterruptedException {
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    new Server().run();
                } catch (IOException ioe) {
                    System.out.println(ioe);
                }


            }

        }).start();

        System.out.println("Waiting for the Server to come up");
        Thread.sleep(500);

        new Client().run();
    }

}

There may be an issue in this solution when the client sends a \r as new line separator and the file starts with \n. The server may count the \n as part of the line separator and the file will be corrupt (one byte will be missing).

andih
  • 5,570
  • 3
  • 26
  • 36