Search code examples
javasocketsprintwriterdatainputstreaminputstreamreader

Client socket will not receive data from server


My issue is that in my client, dis.read() is returning -1 causing it to never actually receive the file. The only thing that I can think of is that because I use a PrintWriter and a BufferedReader before this section, the dis.read() thinks that all data has been received already.

Client Code:

public static void receiveFile(String serverAddress, int port, String fileName, String fileOut) throws IOException {
    Socket client = new Socket(serverAddress, port);
    client.setSoTimeout(5000);
    PrintWriter out = new PrintWriter(client.getOutputStream(), true);
    BufferedReader input = new BufferedReader(new InputStreamReader(client.getInputStream()));

    try {
        out.println("101|" + fileName + "\n");

        if (input.readLine().equals("201")) {
            int br;
            byte[] data = new byte[4096];

            DataInputStream dis = new DataInputStream(client.getInputStream());
            FileOutputStream fos = new FileOutputStream(fileOut);

            while ((br = dis.read(data, 0, data.length)) != -1){
                fos.write(data, 0, br);
            }

            fos.close();
            dis.close();
        }
    } catch (SocketTimeoutException ste) {
        ste.printStackTrace();
        client.close();
    }
}

Server Code:

private void sendFile(String filename, Socket client) throws IOException {
    int br;
    byte[] data = new byte[4096];
    PrintWriter out = new PrintWriter(client.getOutputStream(), true);

    out.println("201\n");

    DataOutputStream dos = new DataOutputStream(client.getOutputStream());
    FileInputStream fis = new FileInputStream(MeshFS.properties.getProperty("repository") + filename);

    while ((br = fis.read(data, 0, data.length)) != -1) {
        dos.write(data, 0, br);
        dos.flush();
    }

    fis.close();
    dos.close();
}

private String receiveRequest(Socket client) {
    String requestPart;
    String requestFull = "";
    try {
        BufferedReader input = new BufferedReader(new InputStreamReader(client.getInputStream()));

        while (((requestPart = input.readLine()) != null) && (requestFull.length() < 2048)) {
            if (requestPart.equals("")) break;
            requestFull = requestFull + requestPart;
        }

        return requestFull;
    } catch (IOException ioe) {
        return requestFull;
    }
}

private void processRequest(String request, Socket out) {

    if (request != null) {
        try {
            String[] requestParts = request.split("\\|");
            if (requestParts[0].equals("101")) {            //101:Get file
                sendFile(requestParts[1], out);

            } else {
                badRequest(out, request);
            }
        } catch (Exception e) {
            badRequest(out, request);
            e.printStackTrace();
        }
    }
}

    public void run() {
        while (!Thread.interrupted()) {
            try {
                server.setSoTimeout(1000);
                Socket client = server.accept();
                client.setSoTimeout(timeout);
                processRequest(receiveRequest(client), client);
                client.close();
            } catch (SocketTimeoutException ste) {
            } catch (IOException io) {
                io.printStackTrace();
            }
        }
        System.out.println("Socket closed");
}

Is there something that I'm missing or forgetting to include? Am I not flushing something or not clearing something?


Solution

  • Okay, I guess I have found the mistake. I made some experiments and found out that InputStream's behave weird if multiple objects try to read from them. In your case, its very likely the BufferedReader and the DataInputStream in your client's receiveFile method causing the problem by trying to read from the same inputStream. I suggest using the DataInputStream to also read the first line so you don't have to create a BufferedReader. Even though the DataInputStream.readLine() method is deprecated, it should still do well in your case.

    I edited the clients receiveFile method to use the DataInputStream to read the first line. Hope it works!

    public static void receiveFile(String serverAddress, int port, String fileName, String fileOut) throws IOException {
        Socket client = new Socket(serverAddress, port);
        client.setSoTimeout(5000);
        PrintWriter out = new PrintWriter(client.getOutputStream(), true);
        DataInputStream dis = new DataInputStream(client.getInputStream());
    
        try {
            out.println("101|" + fileName + "\n");
    
            if (dis.readLine().equals("201")) {
                int br;
                byte[] data = new byte[4096];
    
                FileOutputStream fos = new FileOutputStream(fileOut);
    
                while ((br = dis.read(data, 0, data.length)) != -1){
                    fos.write(data, 0, br);
                }
    
                fos.close();
                dis.close();
            }
        } catch (SocketTimeoutException ste) {
            ste.printStackTrace();
            client.close();
        }
    }