HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Transfer log file between client and server while updating files automatically

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
filewhilelogserverupdatingautomaticallyclientbetweenfilesand

Problem

All this code does is transfer the files. In order to make changes to the file, one has to re-transfer the file. During this time, I stand by to automate the update operation, where the server listens to the files and updates them automatically whenever any changes are made.

```
fileserver.java
import java.io.*;
import java.net.*;
import java.util.*;
public class FileServer {

private static ServerSocket serverSocket;
private static Socket clientSocket = null;

public static void main(String[] args) throws IOException {

try {
serverSocket = new ServerSocket(13850);// creating a new serversocket
System.out.println("Server started.");
} catch (Exception e)// catches errors and display them to the user for eg in case the port is busy we may specify a different port
{
System.err.println("Port already in use.");
System.exit(1);
}

while (true)
{
try {
clientSocket = serverSocket.accept();// establishing the connection
System.out.println("Accepted connection : " + clientSocket);

Thread t = new Thread(new CLIENTConnection(clientSocket));
/creating thread for clientconnection.java file and sending socket as an object thus everytime a connection is established a new thread/process is generated through which the file is sent and recieved/
t.start();// executing the thread. here the new process or thread is created and ready to be implemented

} catch (Exception e) // catches error if any and displays it in the terminal/command prompt
{
System.err.println("Error in connection attempt.");
}
}
}
}

clientconnection.java
import java.util.*;
import java.net.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.lang.String;

public class CLIENTConnection implements Runnable {

private Socket clientSocket;
private BufferedReader in = null;

public CLIENTConnection(Socket client) {
this.clientSocket = client;
}

@Override
public void run() {
try {
in = new BufferedReader(new InputStreamReader(
clie

Solution

Your socket communication protocol is asymmetrical..... the client-side cannot correctly send files larger than 2GB (though the server side looks like it can handle it).

Additionally, your client-side code reads the entire file in to memory.... which is wasteful and unnecessary.

Using the functions available in Java7, you should be using try-with-resources. As it is, you are not closing your sockets correctly, and you're not closing file-handles right either.

Additionally, your methods should complete just a single function. Your sendFile method does user-input as well as the network transfer. I would recommend that you take the user-input out of the method. The receiveFile side of things also has hard-coded file names and locations. I recommend parameterizing it.

Finally, you do not do anything to trap problems with file-changes that may happen mid-transfer, and your error-handling in general is a problem.

I have taken these two methods and re-structured them in a way that:

  • has single functionality in each method.



  • does correct resource-closing (even in exceptional conditions)



  • is symmetrical (you can send and receive large files)



  • handles cases where the file changes mid-send, or is not completely received.



  • uses the socket send/recieve buffer-sizes to set the right size byte-buffer arrays



The methods take some input parameters that are not part of your specification. This is to ensure single-responsibility is maintained.

The exception handling is still not great, but would need to conform to your overall system.

Consider the methods...
receiveFile:

public static final void receiveFile(File outdir, Socket sock) {
    try (DataInputStream clientData = new DataInputStream(new BufferedInputStream(sock.getInputStream()))) {

        String fileName = clientData.readUTF();
        
        try (OutputStream output = new BufferedOutputStream(new FileOutputStream(new File(outdir, "received_from_client_" + fileName)))) {
            long size = clientData.readLong();
            long bytesRemaining = size;
            byte[] buffer = new byte[sock.getReceiveBufferSize()];
            int bytesRead = 0;
            while (bytesRemaining > 0 && (bytesRead = clientData.read(buffer, 0, (int) Math.min(buffer.length, bytesRemaining))) >= 0) {
                output.write(buffer, 0, bytesRead);
                bytesRemaining -= bytesRead;
            }
            output.flush();
            if (bytesRemaining > 0) {
                throw new IllegalStateException("Unable to read entire file, missing " + bytesRemaining + " bytes");
            }
            if (clientData.read() >= 0) {
                throw new IllegalStateException("Unexpected bytes still on the input from the client");
            }
        }

    } catch (IOException ex) {
        System.err.println("Unexpected Client error: " + ex.getMessage());
        ex.printStackTrace();
    }
    
}


sendFile:

public static void sendFile(String fileName, String host, int port) throws IOException {

    File myFile = new File(fileName);
    long expect = myFile.length();
    try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile));
            Socket sock = new Socket(host, port);
            DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream()))) {
        
        byte[] buffer = new byte[sock.getSendBufferSize()];
        dos.writeUTF(myFile.getName());
        dos.writeLong(expect);
        
        long left = expect;
        int inlen = 0;
        while (left > 0 && (inlen = bis.read(buffer, 0, (int)Math.min(left, buffer.length))) >= 0) {
            dos.write(buffer, 0, inlen);
            left -= inlen;
        }
        dos.flush();
        if (left > 0) {
            throw new IllegalStateException("We expected " + expect + " bytes but came up short by " + left);
        }
        if (bis.read() >= 0) {
            throw new IllegalStateException("We expected only " + expect + " bytes, but additional data has been added to the file");
        }
    }
}


I have tested this using some junk data I have, and the main method:

```
public static void main(String[] args) {

File outdir = new File("copiedfiles");
if (!outdir.isDirectory()) {
outdir.mkdirs();
}

final int port = 13850;
final String host = "localhost";

Runnable client = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
sendFile("core.20131214.230701.4868.0001.dmp", host, port);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
};

Thread clientthread = new Thread(client);
clientthread.setDaemon(true);
clientthread.start();

try (ServerSocket ssocket = new ServerSocket(port)) {
Socket clientsock = ssocket.accept();
receiveFile(outdir, clientsock);
} c

Code Snippets

public static final void receiveFile(File outdir, Socket sock) {
    try (DataInputStream clientData = new DataInputStream(new BufferedInputStream(sock.getInputStream()))) {

        String fileName = clientData.readUTF();
        
        try (OutputStream output = new BufferedOutputStream(new FileOutputStream(new File(outdir, "received_from_client_" + fileName)))) {
            long size = clientData.readLong();
            long bytesRemaining = size;
            byte[] buffer = new byte[sock.getReceiveBufferSize()];
            int bytesRead = 0;
            while (bytesRemaining > 0 && (bytesRead = clientData.read(buffer, 0, (int) Math.min(buffer.length, bytesRemaining))) >= 0) {
                output.write(buffer, 0, bytesRead);
                bytesRemaining -= bytesRead;
            }
            output.flush();
            if (bytesRemaining > 0) {
                throw new IllegalStateException("Unable to read entire file, missing " + bytesRemaining + " bytes");
            }
            if (clientData.read() >= 0) {
                throw new IllegalStateException("Unexpected bytes still on the input from the client");
            }
        }

    } catch (IOException ex) {
        System.err.println("Unexpected Client error: " + ex.getMessage());
        ex.printStackTrace();
    }
    
}
public static void sendFile(String fileName, String host, int port) throws IOException {

    File myFile = new File(fileName);
    long expect = myFile.length();
    try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile));
            Socket sock = new Socket(host, port);
            DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream()))) {
        
        byte[] buffer = new byte[sock.getSendBufferSize()];
        dos.writeUTF(myFile.getName());
        dos.writeLong(expect);
        
        long left = expect;
        int inlen = 0;
        while (left > 0 && (inlen = bis.read(buffer, 0, (int)Math.min(left, buffer.length))) >= 0) {
            dos.write(buffer, 0, inlen);
            left -= inlen;
        }
        dos.flush();
        if (left > 0) {
            throw new IllegalStateException("We expected " + expect + " bytes but came up short by " + left);
        }
        if (bis.read() >= 0) {
            throw new IllegalStateException("We expected only " + expect + " bytes, but additional data has been added to the file");
        }
    }
}
public static void main(String[] args) {
    
    File outdir = new File("copiedfiles");
    if (!outdir.isDirectory()) {
        outdir.mkdirs();
    }
    
    final int port = 13850;
    final String host = "localhost";
    
    Runnable client = new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
                sendFile("core.20131214.230701.4868.0001.dmp", host, port);
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    
    Thread clientthread = new Thread(client);
    clientthread.setDaemon(true);
    clientthread.start();
    
    try (ServerSocket ssocket = new ServerSocket(port)) {
        Socket clientsock = ssocket.accept();
        receiveFile(outdir, clientsock);
    } catch (IOException e) {
        e.printStackTrace();
    }
    
}

Context

StackExchange Code Review Q#29478, answer score: 3

Revisions (0)

No revisions yet.