Sending name of the file then file itself - java

I want to make my server to be able to get the name of the file that will be sent to it and then after getting that file it could save it in new location with right name.
Here is the server code:
class TheServer {
public void setUp() throws IOException { // this method is called from Main class.
ServerSocket serverSocket = new ServerSocket(1991);
System.out.println("Server setup and listening...");
Socket connection = serverSocket.accept();
System.out.println("Client connect");
System.out.println("Socket is closed = " + serverSocket.isClosed());
BufferedReader rd = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String str = rd.readLine();
System.out.println("Recieved: " + str);
rd.close();
InputStream is = connection.getInputStream();
int bufferSize = connection.getReceiveBufferSize();
FileOutputStream fos = new FileOutputStream("C:/" + str);
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte[] bytes = new byte[bufferSize];
int count;
while ((count = is.read(bytes)) > 0) {
bos.write(bytes, 0, count);
}
bos.flush();
bos.close();
is.close();
connection.close();
serverSocket.close();
}
}
and here is the client code:
public class TheClient {
public void send(File file) throws UnknownHostException, IOException { // this method is called from Main class.
Socket socket = null;
String host = "127.0.0.1";
socket = new Socket(host, 1991);
// Get the size of the file
long length = file.length();
if (length > Integer.MAX_VALUE) {
System.out.println("File is too large.");
}
BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
wr.write(file.getName());
wr.flush();
byte[] bytes = new byte[(int) length];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());
int count;
while ((count = bis.read(bytes)) > 0) {
out.write(bytes, 0, count);
}
out.flush();
out.close();
fis.close();
bis.close();
socket.close();
}
}
I made few test of my own and it seems that my client is sending the name of the file right, but somehow server gets it wrong. For example if my client tells that name of the file is "test.txt" my server gets it for example like "test.txt´--------------------" or "test.txtPK". I can't understand why it does't get the name normally. Anyone knows why this happens? Or is there an easier way to do this? And my second question is, how can I use this not only in localhost but everywhere? I tried changing my host to my IP adress but it didnt work. Thanks.

You never send end of line after the filename. Therefore, when server reads using readLine() it will read all characters until it find first end of line which may be somewhere in file content. Sometimes it's after '-----' and sometimes after 'PK'.

Related

File Transfer function freezes after first success

I have attempted to write a program that simply sends files from the client to server. The program has a gui where you enter the file path and what you want the new filename to be on the server. The program works fine for the first send but freezes on the second send and the second file does not get written to server. Any help would be appreciated im really stuck thank you guys so much in advance.
Client Code
ServerSocket serverSocket;
public void sendFile(String filePath, String fileFieldName)throws IOException{
//Parameters filePath is a full direct path of file to be sent
//Example of filePath "C:\Users\Someone\Desktop\Capture3333333.PNG"
//FileFieldName is the desired name and extension of file being sent
// i removed my server ip and just put in a string for demonstration
Socket socket = new Socket("IP GOES HERE", 5557);
System.out.println("Is sending?");
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
DataOutputStream dos = new DataOutputStream(bos);
File files = new File(filePath);
long length = files.length();
dos.writeLong(length);
dos.writeUTF("\\"+ fileFieldName);
FileInputStream fis = new FileInputStream(filePath);
BufferedInputStream bis = new BufferedInputStream(fis);
int theByte = 0;
while((theByte = bis.read()) != -1) bos.write(theByte);
bis.close();
bos.flush();
dos.close();
}
Server Code
ServerSocket serverSocket;
public void fileListenThread () throws IOException {
while(true){//This is so the socket keeps listening
serverSocket = new ServerSocket(5557);
Socket socket = serverSocket.accept();
if(socket.isConnected()){
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
DataInputStream dis = new DataInputStream(bis);
File files ;
long fileLength = dis.readLong();//This reads file length from client
String fileName = dis.readUTF();//This reads filename from client
files = new File( System.getProperty("user.home") + "\\Desktop\\Top-Brand\\Images\\" + fileName );//File received from client is written to this path
FileOutputStream fos = new FileOutputStream(files);
BufferedOutputStream bos = new BufferedOutputStream(fos);
for(int j = 0; j < fileLength; j++)
bos.write(bis.read());
bos.flush();
bos.close();
dis.close();
}
}
}
Move the line
serverSocket = new ServerSocket(5557);
out of the while loop. It should be before the loop, not inside it. If you put it in the loop, then after each file transfer, you will be creating another server socket which will then fail to bind because the old one is still there.
RESOLVED - My server socket was inside the loop causing a net bind exception, here is working code for server, client works just fine
ServerSocket serverSocket;
public void fileListenThread () throws IOException {
serverSocket = new ServerSocket(5557);
while(true){//This is so the socket keeps listening
Socket socket = serverSocket.accept();
if(socket.isConnected()){
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
DataInputStream dis = new DataInputStream(bis);
File files ;
long fileLength = dis.readLong();//This reads file length from client
String fileName = dis.readUTF();//This reads filename from client
files = new File( System.getProperty("user.home") + "\\Desktop\\Top-Brand\\Images\\" + fileName );//File received from client is written to this path
FileOutputStream fos = new FileOutputStream(files);
BufferedOutputStream bos = new BufferedOutputStream(fos);
for(int j = 0; j < fileLength; j++)
bos.write(bis.read());
bos.flush();
bos.close();
dis.close();
}
}
}

Java IO Server Client read and process users input

I have a simple Fileserver and Client (code from the web) that let me send files to my other laptop inside my home LAN. Now, the file sent from the server to the client is hardcoded but i want to prompt user at client-side to input a filename, send it to the server and send back the specified file. My code looks like this:
Server
import java.net.*;
import java.io.*;
public class Server {
public static void main(String[] args) {
BufferedOutputStream outputStream;
BufferedInputStream inputStream;
FileInputStream fileInput;
String file = "C:/java/file.mp4";
try {
ServerSocket socket = new ServerSocket(12345);
while(true) {
Socket clientSocket = socket.accept();
outputStream = new BufferedOutputStream(clientSocket.getOutputStream());
fileInput = new FileInputStream(file);
inputStream = new BufferedInputStream(fileInput);
int packetToSend = -1;
byte[] buffer = new byte[8192];
while((packetToSend = inputStream.read(buffer)) > -1) {
outputStream.write(buffer, 0, packetToSend);
System.out.println("sending " + packetToSend + " bytes");
outputStream.flush();
}
}
}
catch(Exception e) {
e.printStackTrace();
}
}
}
And thats the Client Code (IPAdress of the Server is argument s[0] and the path to save the file is s[1] in main method.
import java.net.*;
import java.io.*;
public class Client {
public static void main(String[] s) {
try {
String address = new String(s[0]);
String fileToSave = new String(s[1]);
Socket socket = new Socket(address,12345);
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
FileOutputStream fos = new FileOutputStream(fileToSave);
int n;
byte[] buffer = new byte[8192];
System.out.println("Connected");
while ((n = bis.read(buffer)) > 0) {
System.out.println("received "+n+" bytes");
fos.write(buffer, 0, n);
fos.flush();
}
System.out.println("recieved");
}
catch(Exception e) {
e.printStackTrace();
}
}
}
I want to promt the user on client side to input a filename after client is connected to send to the server and the server should send that file.
i tried to put this in client side after System.out.println("connected");
System.out.print("Insert filename to download: ");
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String input = null;
try {
input = reader.readLine();
} catch (IOException ioe) {
System.out.println("Eingabe konnte nicht verarbeitet werden!");
System.exit(1);
}
System.out.println("Eingabe: " + input);
and on server side i put this after outputStream = new BufferedOutputStream(clientSocket.getOutputStream()); to override the hardcoded filename at the beginning of server class.
inputStream = new BufferedInputStream(clientSocket.getInputStream());
fileInputStream = new FileInputStream(inputStream);
fileInputStream = new BufferedInputStream(fileInput);
Once a connection is established, client side is idle (cant input something) and server side does nothing after writing out to console "new connection".
how can i solve this please?
The client sends to the server the filename. So first you must extract the filename from the socket's input stream. To do that you need to establish a protocol for how information will be sent. This is critical when dealing with TCP streams, which is different from UDP datagrams. Typically two newlines is used to convey the end of a message. But because it is not normal for a filename to have a newline in it, we will use one newline to convey end of message.
We can then use Scanner to extract the filename from the client's socket.
String fileName;
Scanner scanner = new Scanner (clientSocket.getInputStream());
while(scanner.hasNextLine())
{
fileName = scanner.nextLine();
break;
}
fileInputStream = new FileInputStream(fileName);
fileInputStream = new BufferedInputStream(fileInput);
In this example the fileName must be the absolute path to that file as its sits in the server's file system. In future versions you might want to use a directory on the server where files are stored and the client can give you the relative path to file from that directory. Here is how that would look like.
String fileName;
Scanner scanner = new Scanner (clientSocket.getInputStream());
while(scanner.hasNextLine())
{
fileName = scanner.nextLine();
break;
}
fileInputStream = new FileInputStream(FILE_DIR + fileName);
fileInputStream = new BufferedInputStream(fileInput);
The variable FILE_DIR would look something like:
static String FILE_DIR = "C:/java/";
And the file that the client would send over would just be file.mp4
EDIT 1:
Here is the Client code with the recommendations. Please note that this test quality code, not production code.
import java.net.*;
import java.io.*;
public class Client {
static String FILE_DIR = "./";
public static void main(String[] s) throws IOException {
/**
* Establish socket using main args.
*/
String address = s[0];
while (true) {
/**
* Get the file name from the user.
*/
System.out.print("Insert filename to download: ");
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String fileName = null;
try {
fileName = reader.readLine();
} catch (IOException ioe) {
System.out.println("Eingabe konnte nicht verarbeitet werden!");
System.exit(1);
}
System.out.println("Eingabe: " + fileName);
/**
* Create the socket.
*/
Socket socket = new Socket(address, 12345);
/**
* With file name in hand, proceed to send the filename to the
* server.
*/
//...put in try-with-resources to close the outputstream.
try (BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream())) {
System.out.println("Connected: Sending file name to server.");
//...send file name plus a newline.
bos.write((fileName + '\n').getBytes());
bos.flush();
/**
* Get the file contents and save to disk.
*/
//...wrap input stream in DataInpuStream for portability.
//...put in try-with-resource to close the input stream.
try (BufferedInputStream bis = new BufferedInputStream(new DataInputStream(socket.getInputStream()))) {
DataOutputStream fos = new DataOutputStream(new FileOutputStream(fileName));
int n;
byte[] buffer = new byte[8192];
System.out.println("Connected: Recieving file contents from server.");
while ((n = bis.read(buffer)) > 0) {
System.out.println("received " + n + " bytes");
fos.write(buffer, 0, n);
fos.flush();
}
System.out.println("recieved");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
and here's the server code. Please note the server is retrieving the file from local directory called ./files/, please change that to whatever directory you want.
import java.net.;
import java.io.;
import java.util.Scanner;
public class Server {
static String FILE_DIR = "./files/";
public static void main(String[] args) {
BufferedInputStream inputStream;
FileInputStream fileInput;
try {
ServerSocket socket = new ServerSocket(12345);
while (true) {
Socket clientSocket = socket.accept();
/**
* Get the file name from the client. File name is one per line.
*/
//...put in trye-with-resources to close InputStream for us.
try (InputStream inputFromClient = clientSocket.getInputStream()) {
System.out.println("Connected: Getting file name from client.");
Scanner scanner = new Scanner(inputFromClient);
String fileName;
if (scanner.hasNextLine()) {
fileName = scanner.nextLine();
System.out.println("File name = " + fileName);
} else {
//...no line found, continue. consider logging an error or warning.
continue;
}
/**
* With fileName in hand, we can proceed to send the
* contents of the file to the client.
*/
fileInput = new FileInputStream(fileName);
//...use DataInputStream for more portable code
DataInputStream dataInput = new DataInputStream(fileInput);
inputStream = new BufferedInputStream(dataInput);
int packetToSend = -1;
byte[] buffer = new byte[8192];
//...consider closing the OutputStream to let the client know.
//...use try-with-resource to close the outputStream for us.
//...wrap your outputStream in DataOutputStream
try (BufferedOutputStream outputStream = new BufferedOutputStream(new DataOutputStream(clientSocket.getOutputStream()))) {
while ((packetToSend = inputStream.read(buffer)) > -1) {
outputStream.write(buffer, 0, packetToSend);
System.out.println("sending " + packetToSend + " bytes");
outputStream.flush();
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

Send request line + File using Sockets - java

I am trying to send a "request line" and a file through a socket.
Client (sender)
Socket socket = new Socket(hostName, SOCKET_PORT);
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
FileInputStream fis = new FileInputStream(fileName);
os.writeBytes("PUT c:\dev\foo\helloworld.txt" + "\r\n")
byte[] buffer = new byte[1024];
int bytes;
while((bytes = fis.read(buffer)) != -1 ) {
try {
os.write(buffer, 0, bytes);
} catch (IOException e) {e.printStackTrace();}
}
Sever (receiver)
ServerSocket serverSocket = new ServerSocket(SOCKET_PORT);
Socket clientSoc = serverSocket.accept();
InputStream inputStream = clientSoc.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String requestLine = bufferedReader.readLine();
File currentFile = (File)new ObjectInputStream(inputStream).readObject(); //This doesn't work
byteSequence = new byte[new Long(currentFile.length()).intValue()];
for(int i =0; i<currentFile.length();i++){
byteSequence[i] = (byte)clientSoc.getInputStream().read();
}
try {
FileOutputStream newFile = new FileOutputStream(currentFile.getName());
newFile.write(byteSequence,0, byteSequence.length);
} catch (IOException e) {e.printStackTrace();}
I am able to read the request line on the server but when I attempt to read the file it throws an exception (line below).
File currentFile = (File)new ObjectInputStream(inputStream).readObject();
java.io.Stream.CorruptedException:
java.io.StreamCorruptedException: invalid stream header: 0A48656C
What exactly am I doing wrong?
You are trying to access an object that was not even passed to the socket.. you only passed a byte of string to the server but you never pass an Object to the server using the ObjectOutputStream..

Resume file upload/download after lost connection (Socket programming)

I'm writing a program to download/upload a file between a client and server using socket programming. The code i've written till now works in the sense that i can sucesfully transfer files. However , if a connection fails due to problem in the network/client/server while a download / upload is occuring.. i need to RESUME the download/upload from the original point(Do not want the originally sent data to be resent). I'm not sure how to go about this. I'm reading the file into a byte array and sending it across the network. My initial idea is that everytime i'm downloading.. i should check if the file already exists and read the data into a byte array --> send the data to the server for comparison and then return the remaining data from the server file by comparing the two byte arrays. But this seems inefficient and takes away the point of resuming a download(since i'm sending the data again).
Note: The file name is an unique identifier.
I would really appreciate it if anybody could give me suggestions as to how i should implement the file resume functionality?
Server side code:
package servers;
import java.io.*;
import java.net.*;
import java.util.Arrays;
public class tcpserver1 extends Thread
{
public static void main(String args[]) throws Exception
{
ServerSocket welcomeSocket = null;
try
{
welcomeSocket = new ServerSocket(5555);
while(true)
{
Socket socketConnection = welcomeSocket.accept();
System.out.println("Server passing off to thread");
tcprunnable tcprunthread = new tcprunnable(socketConnection);
Thread thrd = new Thread(tcprunthread);
thrd.start();
System.out.println(thrd.getName());
}
}
catch(IOException e){
welcomeSocket.close();
System.out.println("Could not connect...");
}
}
}
class tcprunnable implements Runnable
{
Socket socke;
public tcprunnable(Socket sc){
socke = sc;
}
public void download_server(String file_name)
{
System.out.println("Inside server download method");
try
{
System.out.println("Socket port:" + socke.getPort());
//System.out.println("Inside download method of thread:clientsentence is:"+clientSentence);
// Create & attach output stream to new socket
OutputStream outToClient = socke.getOutputStream();
// The file name needs to come from the client which will be put in here below
File myfile = new File("D:\\ "+file_name);
byte[] mybytearray = new byte[(int) myfile.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myfile));
bis.read(mybytearray, 0, mybytearray.length);
outToClient.write(mybytearray, 0, mybytearray.length);
System.out.println("Arrays on server:"+Arrays.toString(mybytearray));
outToClient.flush();
bis.close();
}
catch(FileNotFoundException f){f.printStackTrace();}
catch(IOException ie){
ie.printStackTrace();
}
}
public void upload_server(String file_name){
try{
byte[] mybytearray = new byte[1024];
InputStream is = socke.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileOutputStream fos = new FileOutputStream("D:\\ "+file_name);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
bos.write(mybytearray, 0, bytesRead);
do {
baos.write(mybytearray);
bytesRead = is.read(mybytearray);
}
while (bytesRead != -1);
bos.write(baos.toByteArray());
System.out.println("Array on server while downloading:"+Arrays.toString(baos.toByteArray()));
bos.close();
}
catch(FileNotFoundException fe){fe.printStackTrace();}
catch(IOException ie){ie.printStackTrace();}
}
#Override
public void run()
{
try
{
System.out.println("Server1 up and running" + socke.getPort());
// Create & attach input stream to new socket
BufferedReader inFromClient = new BufferedReader
(new InputStreamReader(socke.getInputStream()));
// Read from socket
String clientSentence = inFromClient.readLine();
String file_name = inFromClient.readLine();
System.out.println("Sever side filename:" + file_name);
try{
if(clientSentence.equals("download"))
{
download_server(file_name);
}
else if(clientSentence.equals("upload"))
{
upload_server(file_name);
System.out.println("Sever side filename:" + file_name);
}
else
{
System.out.println("Invalid input");
}
}
catch(NullPointerException npe){
System.out.println("Invalid input!");
}
socke.close();
}
catch(IOException e)
{
e.printStackTrace();
System.out.println("Exception caught");
}
}
}
Client side code:
package clients;
import java.io.*;
import java.net.*;
import java.util.Arrays;
public class tcpclient1
{
public static void main (String args[]) throws Exception
{
// Create input stream to send sentence to server
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
Socket clientSocket = null;
while(true){
System.out.println("Please enter the server you want to use");
System.out.println("Enter 1 for Server 1 and 2 for Server2");
String server_choice = inFromUser.readLine();
if(server_choice.equals("1")){
// Create client socket to connect to server
// The server to use will be specified by the user
clientSocket = new Socket("localhost",5555);
break;
}
else if(server_choice.equals("2"))
{
clientSocket = new Socket("localhost",5556);
break;
}
else
{
System.out.println("Invalid entry");
}
}
System.out.println("Please enter download for dowloading");
System.out.println("Please enter upload for uploading");
// sentence is what'll be received from input jsp
String sentence = inFromUser.readLine();
if(sentence.equals("download"))
{
download_client(clientSocket,sentence);
}
else if(sentence.equals("upload"))
{
upload_client(clientSocket,sentence);
}
else
{
System.out.println("Invalid input");
}
clientSocket.close();
}
public static void download_client(Socket clientSocket , String sentence)
{
try{
// Create output stream attached to socket
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
// Send line to server
outToServer.writeBytes(sentence+'\n');
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter the name of file to download:");
String file_to_download = inFromUser.readLine();
if(searching(file_to_download))
{
// Read local file and send that to the server for comparison
// DONT THINK THIS IS THE RIGHT WAY TO GO ABOUT THINGS SINCE IT BEATS THE PURPOSE OF RESUMING A DOWNLOAD/UPLOAD
}
// Send filetodownload to server
outToServer.writeBytes(file_to_download+'\n');
byte[] mybytearray = new byte[1024];
InputStream is = clientSocket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileOutputStream fos = new FileOutputStream("E:\\ "+file_to_download);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
bos.write(mybytearray, 0, bytesRead);
do {
baos.write(mybytearray);
bytesRead = is.read(mybytearray);
}
while (bytesRead != -1);
bos.write(baos.toByteArray());
System.out.println("Array on client while downloading:"+Arrays.toString(baos.toByteArray()));
bos.close();
}
catch(FileNotFoundException fe){fe.printStackTrace();}
catch(IOException ie){ie.printStackTrace();}
}
public static void upload_client(Socket clientSocket, String sentence)
{
try{
// Create output stream attached to socket
DataOutputStream outToServer1 = new DataOutputStream(clientSocket.getOutputStream());
// Send line to server
outToServer1.writeBytes(sentence+'\n');
System.out.println("In the client upload method");
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter the name of file to upload:");
String file_to_upload = inFromUser.readLine();
//System.out.println("Cline side file name:"+file_to_upload);
outToServer1.writeBytes(file_to_upload+'\n');
System.out.println(file_to_upload);
OutputStream outtoserver = clientSocket.getOutputStream();
File myfile = new File("E:\\ "+file_to_upload);
byte[] mybytearray = new byte[(int) myfile.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myfile));
bis.read(mybytearray, 0, mybytearray.length);
outtoserver.write(mybytearray, 0, mybytearray.length);
System.out.println("filename:"+file_to_upload+"Arrays on client while uploading:"+Arrays.toString(mybytearray));
outtoserver.flush();
bis.close();
}
catch(FileNotFoundException fe){fe.printStackTrace();}
catch(IOException ie){ie.printStackTrace();}
}
public static boolean searching(String file_name)
{
String file_path = "E:\\ "+file_name;
File f = new File(file_path);
if(f.exists() && !f.isDirectory()) { return true; }
else
return false;
}
}
The above code runs fine for transferring files between the client and server.
Again , would really appreciate any help!
There are many ways which you can do this, I suggest you to create a separate type of request to the server that accepts the file's name and file position which is the position where in the file where the connection failed.
That's how you will get the file from the server in the client's side:
int filePosition = 0;
InputStream is = clientSocket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
do {
baos.write(mybytearray);
bytesRead = is.read(mybytearray);
if(bytesRead != -1)
filePosition += bytesRead;
}
while (bytesRead != -1);
Now if the connection got interrupted for some reason you can send a request again to the server with the same file name and the filePosition, and the server will send the file back like this:
OutputStream outToClient = socke.getOutputStream();
// The file name needs to come from the client which will be put in here below
File myfile = new File("D:\\ "+file_name);
byte[] mybytearray = new byte[(int) myfile.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myfile));
bis.skip(filePosition) //Advance the stream to the desired location in the file
bis.read(mybytearray, 0, mybytearray.length);
outToClient.write(mybytearray, 0, mybytearray.length);
System.out.println("Arrays on server:"+Arrays.toString(mybytearray));
outToClient.flush();
bis.close();
And in the client you can open the file stream and specify append = true in the constructor like this:
FileOutputStream fos = new FileOutputStream("D:\\ "+file_name, true);
This could be one way to do this, there are a lot more options. And I also suggest verify the files after the transfer using some hash function like MD5 for example, it creates unique stamp for a given input and it always outputs same result for the same input, which means, you can create the stamp from the same file both in the server and in the client and if the file is truly the same, it will generate the same stamp. Since the stamp's size is very small relative to the file it self and it is also fixed, it can be send between the client/server without much overhead.
You can generate an MD5 hash with this code:
MessageDigest md = MessageDigest.getInstance("MD5");
try (InputStream is = Files.newInputStream(Paths.get("file.txt"))) {
DigestInputStream dis = new DigestInputStream(is, md);
/* Read stream to EOF as normal... */
}
byte[] digest = md.digest();
(taken from: Getting a File's MD5 Checksum in Java)
Basically, when requesting a download You should attach information about how many bytes need to be skipped (0 on new download). You should get this information from part of the file that you have downloaded (read it's size). Server should skip given count of bytes and send back the remainder of file. Client should append this to the existing file. For sanity check, You could add some file hash checking in the end, to ensure You got the file correctly.

Sending large files over socket

I got working over socket file sender, it worked perfectly, but I couldn't send large files with it. Always got heap error. Then I changed the code of client, so it would send file in chunks. Now I can send big files, but there is new problem. Now I recieve small files empty and larger files for example videos can't be played. Here is the code of client that sends file:
public void send(File file) throws UnknownHostException, IOException {
// Create socket
hostIP = "localhost";
socket = new Socket(hostIP, 22333);
//Send file
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
OutputStream os = socket.getOutputStream();
//Sending size of file.
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF(file.getName() + ":" + userName);
byte[] arr = new byte[1024];
try {
int len = 0;
while ((len = dis.read(arr)) != -1) {
dos.write(arr, 0, len);
}
} catch (IOException ex) {
ex.printStackTrace();
}
dos.flush();
socket.close();
}
and here is the server code:
void start() throws IOException {
// Starts server on port.
serverSocket = new ServerSocket(port);
int bytesRead;
while (true) {
connection = serverSocket.accept();
in = connection.getInputStream();
clientData = new DataInputStream(in);
String[] data = clientData.readUTF().split(":");
String fileName = data[0];
String userName = data[1];
output = new FileOutputStream("C:/" + fileName);
long size = clientData.readLong();
byte[] buffer = new byte[1024];
// Build new file
while (size > 0 && (bytesRead = clientData.read(buffer, 0, (int) Math.min(buffer.length, size))) != -1) {
output.write(buffer, 0, bytesRead);
size -= bytesRead;
}
output.close();
}
}
You failed to write out the length of the file to the stream in the client:
long size = clientData.readLong();
So that call in the server is reading the first 8 bytes of the actual file and who knows what that quantity is. You don't have to read the length from the stream since you only wrote a single file. After reading the filename, and username (not very secure is it?) you can just read the stream until EOF. If you ever wanted to send multiple files over the same open socket then you'd need to know the length before reading the file.
Also your buffers for reading are way to small. You should be at a minimum of 8192 instead of 1024. And you'll want to put all .close() in a finally block to make sure your server and clients shutdown appropriately if there is an exception ever.

Categories