patternjavaMinor
Transfer log file between client and server while updating files automatically
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
```
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:
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:
sendFile:
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
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.