Getting file name of file being received on the server - java

I am writing a client/server program where I send a file over sockets. I create a file object in the server code, but I do not know what to call the file as the file the client sends is user-defined.
NOTE: I want to be able to receive larger files e.g. .mp3 files etc.
server code:
try{
ServerSocket servsock = new ServerSocket(123456);
File myFile = new File(/* I dont know how to get the file name here*/);
while (true) {
Socket sock = servsock.accept();
System.out.println("Connection accepted, ip - port - ");
byte[] mybytearray = new byte[(int) myFile.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile));
bis.read(mybytearray, 0, mybytearray.length);
OutputStream os = sock.getOutputStream();
os.write(mybytearray, 0, mybytearray.length);
os.flush();
sock.close();
bis.close();
servsock.close();
}
} catch(IOException e) {
System.out.println("Error");
}

Create a pojo to hold file name and bytes
public class FileObject {
private String fileName;
private byte[] fileData;
//getter/setters
}
Set the file name and data on clientSide
ClientCode
FileObject fileObject = new FileObject();
//set the fileName here
fileObject.setFileName(fileName);
File file = new File(filePath);
if (file.isFile()) {
//set data here
fileObject.setFileData(fileBytes);
}
//Now writing the FileObject object to socket
outputStream.writeObject(fileObject);
ServerCode
//Cast the received input stream to get data and file name
fileObject = (FileObject ) inputStream.readObject();

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();
}
}
}

Send MP3 and JPEG file over socket properly over Socket in java

SERVER (receive file)
String ip=JOptionPane.showInputDialog(this,"Enter Port Number :");
String folder=jTextField2.getText();
try
{
ServerSocket sskt= new ServerSocket(Integer.parseInt(ip));
Socket skt= sskt.accept();
InputStream is= skt.getInputStream();
byte[] bytes= new byte[1024*16];
DataInputStream dis=new DataInputStream(skt.getInputStream());
String ext=dis.readUTF();
System.out.println("extension read");
String path=folder+"/file."+ext;
JOptionPane.showMessageDialog(this, path);
File f= new File(path);
OutputStream output = new FileOutputStream(f);
while(is.read(bytes)>0)
{
output.write(bytes);
System.out.println("byte read");
}
System.out.println("Done!!!");
}
catch(Exception e)
{
System.out.println(e);
}
CLIENT(send File)
String ip=JOptionPane.showInputDialog(this,"enter server ip:");
String port=JOptionPane.showInputDialog(this,"enter port number :");
File file=new File(jTextField1.getText());
String name=file.getName();
String n= name.substring(name.lastIndexOf(".") + 1);
try {
Socket skt=new Socket(ip, Integer.parseInt(port));
OutputStream os= skt.getOutputStream();
DataOutputStream dos= new DataOutputStream(os);
dos.writeUTF(n);
os.flush();
FileInputStream fis= new FileInputStream(file);
BufferedInputStream bis= new BufferedInputStream(fis);
byte[] mybytearray = new byte[(int) file.length()];
bis.read(mybytearray, 0, mybytearray.length);
os.write(mybytearray, 0, mybytearray.length);
JOptionPane.showMessageDialog(this,"Done!!");
os.close();
}
catch (Exception ex) {
System.out.println(ex);
}
i am able to transfer all formats of file bt mp3 and jpeg files do not open properly. Media player is not able to play any mp3 file bt size of file created at server is same as that send by client
anyone can please help me out with this
Usual problem: ignoring the length returned by read(). Your copy loops should both look like this:
while ((count = is.read(bytes)) > 0)
{
output.write(bytes, 0, count);
}
You don't need all that garbage in the client about allocating a correctly sized buffer.

writing into file in a client and NegativeArraySizeException

i have a server which sending thousands of tiny files like below:
static File file = null;
static File temp = null;
private static ServerSocket serverSocket;
private static Socket socket;
public static void main(String[] args) throws FileNotFoundException, IOException
{
serverSocket = new ServerSocket(3000);
socket = serverSocket.accept();
System.out.println("Connected");
File folder = new File("C:...\\Desktop\\thousands_of_tiny_files");
File[] listOfFiles = folder.listFiles();
File result[]=new File[listOfFiles.length];
byte [] bytearray = null;
FileInputStream fin =null;
BufferedInputStream bin = null;
for(int j=0;j<listOfFiles.length;j++){
String path= listOfFiles[j].getPath();
result=sendFile(path);
for(int i=0;i<result.length;i++)
{
fin = new FileInputStream(result[i]);
bin = new BufferedInputStream(fin);
bytearray = new byte [(int)result.length];
bin.read(bytearray,0,bytearray.length);
OutputStream os = socket.getOutputStream();
System.out.println("Sending Files "+ result[i]);
os.write(bytearray,0,bytearray.length);
os.flush();
System.out.println("File transfer completed");
}
}
fin.close();
bin.close();
socket.close();
}
public static File[] sendFile(String path)
{
File folder = new File(path);
File[] listOfFiles = folder.listFiles();
File[] resultt = new File[listOfFiles.length];
for(int i=0;i<listOfFiles.length;i++)
{
temp=listOfFiles[i];
if(temp.isFile() && temp!=null)
resultt[i]=temp;
}
return resultt;
}
it is successfull but my problem is in client side. i dont know how to distinguish between the files and write them seperately into the client.
EDIT2:
I changed the server side code like following using ZipOutputStream but still dont know how to unzip and write it in the client (mostly, dont know how to define the FileOutputStream in client:
for(int i=0;i<result.length;i++)
{
fin = new FileInputStream(result[i]);
bytearray = new byte [(int)result.length];
ZipOutputStream zipOpStream = new ZipOutputStream(socket.getOutputStream());
zipOpStream.putNextEntry(new ZipEntry(result[i].getName()));
System.out.println("Sending Files "+ result[i]);
zipOpStream.write(bytearray,0,bytearray.length);
zipOpStream.flush();
System.out.println("File transfer completed");
}
}
socket.close();
}
and the reciever code:
socket = new Socket("127.0.0.1",3000);
String outDir = "C:...\\Desktop\\here";
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
ZipInputStream zips = new ZipInputStream(bis);
ZipEntry zipEntry = null;
while(null != (zipEntry = zips.getNextEntry())){
String fileName = zipEntry.getName();
File outFile = new File(outDir + "/" + fileName);
System.out.println("----["+outFile.getName()+"], filesize["+zipEntry.getCompressedSize()+"]");
if(zipEntry.isDirectory()){
File zipEntryFolder = new File(zipEntry.getName());
if(zipEntryFolder.exists() == false){
outFile.mkdirs();
}
continue;
}else{
File parentFolder = outFile.getParentFile();
if(parentFolder.exists() == false){
parentFolder.mkdirs();
}
}
System.out.println("ZipEntry::"+zipEntry.getCompressedSize());
FileOutputStream fos = new FileOutputStream(outFile);
int fileLength = (int)zipEntry.getSize();
byte[] fileByte = new byte[fileLength];
zips.read(fileByte);
fos.write(fileByte);
fos.close();
socket.close();
}
now i get an exceptiom"negative NegativeArraySizeException"
Exception in thread "main" java.lang.NegativeArraySizeException
at recieve.Reciever.<init>(Reciever.java:71)
at recieve.Recieve$1.<init>(Recieve.java:28)
at recieve.Recieve.main(Recieve.java:28)
ZipEntry::-1
which probably is because of
int fileLength = (int)zipEntry.getSize();
but how can I solve this? i need the siz of next entry of zip folder for writing into the file.
but the size is in Long not int
How about writing it into a ZipOutputStream where you can receive the file on the other side as a single stream. Once you have the entire output, you can write the reverse code to deflate the zip file and get all the files. Providing a sample code for writing the Zip into your socket stream, you can build your code over this.
Refer this length for a sample Server and Client implementation sending the file using a ZipOutputStream Stick2Code

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.

Categories