0

So i'm building a client/server application in java. There is a functionality that is the client may upload a file to the server. The client side code goes as follows:

public void start () throws IOException {

    while (true ) {
        this.in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
        this.out = new PrintWriter (this.clientSocket.getOutputStream());
        System.out.println("To create an account write -> create account:<username>:<password>");
        System.out.println("To log in with your account write -> log in:<username>:<password>");

        String input = buffer.readLine();
        String parser [] = input.trim().split(":");
        this.out.println(input);
        this.out.flush();


        if ("quit".equals(parser[0])) break;

        if ("create account".equals(parser[0]));

        if ("log in".equals(parser[0])) {
            String answer = in.readLine();
            System.out.println (answer);

            if (answer.equals("Sucesso")) {
                System.out.println ("Para fazer um upload escreva -> upload:<file_path>:<nome_musica>:<nome_autor>:<ano>:<etiquetaVarias>\n");
                System.out.println("Para fazer um download escreva -> download:<id_musica>:<path para onde quer que o download seja feito>\n");
                System.out.println ("Para ver a lista de todas as musicas escreva -> lista musicas\n");
                System.out.println ("Para ver a lista de musicas com uma dada etiqueta escreva -> etiqueta:<nome_etiqueta>\n");
            }

            else ;
        }

        if ("upload".equals(parser[0])) {

            System.out.println("Here");
            File file = new File(parser[1]);
            long length = file.length();
            byte[] bytes = new byte[1000000];
            InputStream inS = new FileInputStream(file);
            OutputStream outS = this.clientSocket.getOutputStream();
            int count;

            System.out.println("Sending");
            while ((count = inS.read(bytes)) > 0) {
                outS.write(bytes, 0, count);

            }
        }
    }
}

The server side code goes as follows:

public void run () {

    try {

        BufferedReader in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
        PrintWriter out = new PrintWriter(this.clientSocket.getOutputStream());
        String s;

        while ((s = in.readLine()) != null) {

            System.out.println("lido: " + s);
            String p = s.trim();
            String parser [] = p.split(":");
            int parser_size = parser.length;


            if ("create account".equals(parser[0])) {
                this.biblioteca.createAccount(parser[1], parser[2]);
            }

            if ("log in".equals(parser[0])) {
                if (this.biblioteca.logIn(parser[1], parser[2])) {
                    out.println("Sucesso");
                    out.flush();
                }

                else {
                    out.println("Falhou! Tente again!");
                    out.flush();
                }
            }

            if ("upload".equals(parser[0])) {
                String categorias [] = new String [parser.length - 5];

                for (int i = 0; i < categorias.length; i++) {
                    categorias [i] = parser[i+5];
                }
                Music nova = new Music (this.biblioteca.get_id(), parser[2], parser[3], parser[4], categorias);
                this.biblioteca.adicionaMusica(nova);
                this.biblioteca.inc_id();

                 InputStream inS = this.clientSocket.getInputStream();
                 File f = new File(parser[1]);
                 String fname = f.getName();
                 OutputStream outS = new FileOutputStream(new File ("music/" + fname + ".xml"));
                 byte[] bytes = new byte[1000000];

                 int count;
                 System.out.println ("Receiving");
                    while ((count = inS.read(bytes)) > 0) {
                        outS.write(bytes, 0, count);
                    }

                 System.out.println("Received");

                 outS.close();
                 inS.close();
            }


        }

    }catch (IOException e) {
        e.printStackTrace();
    }

}

The problem is happening on the last if statement of both classes. everything works as normal, but the server side gets stuck on the "receiving" message and not actually gets to the "received" message unless i terminate the connection. The odd part is that once i terminate the connection, the file gets created and the content are intact which leads me to believe the loop

 while ((count = inS.read(bytes)) > 0) {
              outS.write(bytes, 0, count);
 }

doesn't actually finish for some reason. Can someone help me?

  • have you tried to call `outS.flush()` or even close it after `while` loop in your client code? – Ivan Jan 02 '20 at 16:38
  • i've tried and it fixes it. But it also closes the streams between the sockets which i don't want to happen because i want the client to be able to talk to the server after the upload –  Jan 02 '20 at 16:43
  • Have you tried just `flush()`? Also you are still closing it in your server code – Ivan Jan 02 '20 at 16:44
  • .flush() do not close the socket, it just writes the buffer to the target. .close() closes the socket. – aksappy Jan 02 '20 at 16:55

1 Answers1

0

Your understanding of what is going on is correct. The socket is still alive waiting for more information. What you need now is a message protocol that communicates the length of the data being sent (as well as the type of data, ideally), or that otherwise demarcates when sending is finished (you could use XML or JSON for the later. An xml message would finish with "" or whatever you initial start tag is, and JSON would finish with a close brace (}) that matches the opening open brace ({)

Also, I'd recommend to you that using a reader could get you into trouble if you don't know / can't guarantee the character beforehand, and that reading from the stream line by line is quite inefficient.

Just FYI, if this is useful for you, here's a link to the class I put together years ago for efficiently fetching data from sockets (and the file system): https://sourceforge.net/p/tus/code/HEAD/tree/tjacobs/io/DataFetcher.java it uses listener callbacks and implements Runnable so it can be run in it's own thread.

ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • thank you for your answer. How can i demarcate that the sending is finished? –  Jan 02 '20 at 17:02