i have a client and a server,
1) client should send choose files and send them to server
2) client should send a command message so that the server knows that the incoming is a file not a message (thats why i have "SF" which stands for send file)
3) server receives files and store them somewhere in the system
Also, i dont want to close the socket after i send/receive files (because this is done when the client clicks on disconnect button)
Below is my code but it does not work for some reason, if someone can help me fix it.
Client
public void sendFiles(String file) {
this.out.print("SF");
this.out.flush();
File myfile = new File(file);
// Get the size of the file
long length = myfile.length();
if (length > Integer.MAX_VALUE) {
System.out.println("File is too large.");
}
byte[] bytes = new byte[(int) length];
FileInputStream fis;
try {
fis = new FileInputStream(myfile);
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream out = new BufferedOutputStream(sock.getOutputStream());
int count;
while ((count = bis.read(bytes)) > 0) {
out.write(bytes, 0, count);
}
System.out.println("count "+bytes.length);
// this.out.flush();
out.flush();
// out.close();
fis.close();
bis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Server
public void recvFile() {
InputStream is = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
int bufferSize = 0;
try {
is = sock.getInputStream();
bufferSize = sock.getReceiveBufferSize();
System.out.println("Buffer size: " + bufferSize);
fos = new FileOutputStream("/Users/day/Documents/Parallels/server.txt");
bos = new BufferedOutputStream(fos);
byte[] bytes = new byte[bufferSize];
int count;
while ((count = is.read(bytes)) > 0) {
bos.write(bytes, 0, count);
}
System.out.println("bytes "+bytes.length);
System.out.println("count "+count);
bos.flush();
bos.close();
// is.close();
// sock.close();
} catch (IOException e) {
System.out.println("ERROR" +e);
}
Also in the server side; this is how i jump to the method recvFile();
if (message.contains("SF")) {
recvFile();
}
MORE explanation about my problem:
It does not work in a sense that i dont know if the file is actually sent properly? or the file received properly because i get 0 bytes in the received file. Also, this is the thing i dont want to close the connection because this is a chat so how can i let the server know that this is the end of file?
Can someone help me making the code works because i dont know whats wrong? thanks
Could you kindly elaborate on the error that you are getting. That may help in answering. Because, prima facie the code structure looks fine.
Additionally, I presume that you are using TCP connection for file transfer.
P.S.: I couldn't add a comment to the question, so asking question here.
Related
This question already has answers here:
Java multiple file transfer over socket
(3 answers)
Closed 4 years ago.
I got a really weird problem by sending files over Internet with java Socket. I have a Java server that works pretty fine in LAN, it communicates and transfer files.
The problem is in WAN: when I ran the Server on a remote PC, the Client can communicate with Server, but he'll stuck at 0% when it tries to sends file to the Server. It usually happens with large files (>= of 100 MB), but sometimes happens with small files too.
Please someone help me :), Thank you.
Server Receiving code:
public void ReceiveFile(int fileSize, Socket sock, String fileName, String cmrId, PrintWriter pw){
folderCheck(cmrId);
FileOutputStream fos= null;
BufferedOutputStream bos= null;
try {
int ret;
int bytesRead=0;
fos= new FileOutputStream(cmrId+"/"+fileName); //receive file to User Dedicated folder
bos= new BufferedOutputStream(fos);
//InputStream input= sock.getInputStream();
byte[] bytesArray= new byte[fileSize];
DataInputStream dis= new DataInputStream(sock.getInputStream());
ret= dis.read(bytesArray, 0, bytesArray.length);
bytesRead= ret;
//System.out.println("CmrFoldMan -- Received " + bytesRead + " of " + fileSize); //debug
while(bytesRead<fileSize){
ret= dis.read(bytesArray, bytesRead, (bytesArray.length-bytesRead));
if(ret>=0) bytesRead+=ret;
//System.out.println("CmrFoldMan -- Received " + bytesRead + " of " + fileSize); //debug
}
bos.write(bytesArray, 0, bytesRead);
bos.flush();
upHist= new UpdateHistory(fileName, fileSize, cmrId);
upHist.update();
daysLimit.deleteFilesLimit(fileSize, cmrId); //delete files that exceed memory limit
} catch (IOException ex) {
Logger.getLogger(CmrFolderManager.class.getName()).log(Level.SEVERE, null, ex);
}
finally{
try {
fos.close();
bos.close();
} catch (IOException ex) {
Logger.getLogger(CmrFolderManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Client Sending Code:
public long upload(String fileToSend){
long uploadTimerStart = System.currentTimeMillis(); //start timer
if(contactServerCheckError()) return -1;
try{
pw.println(fileSize);
pw.println(fileName);
Socket sendSock= new Socket(ip, filePort); //connecting to sending file port
DataOutputStream dos= new DataOutputStream(sendSock.getOutputStream());
File file= new File(fileToSend);
int arraySize= (int)file.length(); //used for println only
byte[] array= new byte[1024]; //array is 1024 to use progress bar
fis= new FileInputStream(file);
bis= new BufferedInputStream(fis);
int len;
int tmpBytes=0;
while((len= bis.read(array))>0){
//System.out.println("SendFile " + tmpBytes + " bytes " + "of " + arraySize); //debug
dos.write(array, 0, len);
dos.flush();
tmpBytes+=len;
updateProgressBars(tmpBytes);
updateLabelsPercentage(tmpBytes);
}
} catch (FileNotFoundException ex) {
Logger.getLogger(SendFile.class.getName()).log(Level.SEVERE, null, ex);
return -1;
} catch (IOException ex) {
Logger.getLogger(SendFile.class.getName()).log(Level.SEVERE, null, ex);
return -1;
}
finally{
try{
if(bis!=null) bis.close();
if(os!=null) os.close();
//if(sock!=null) sock.close();
} catch (IOException ex) {
Logger.getLogger(SendFile.class.getName()).log(Level.SEVERE, null, ex);
JOptionPane.showMessageDialog(null, "ERROR " + ex);
return -1;
}
}
long uploadTimerEnd = System.currentTimeMillis(); //end timer
long uploadTimerDelta= uploadTimerEnd - uploadTimerStart;
return uploadTimerDelta;
}
Well... for starters... as far as I can tell, in the receiving code you are creating a byte array that is the size of the destination file,
byte[] bytesArray= new byte[fileSize];
and you keep reading from the input stream, into the byte array, until it is full,
while(bytesRead<fileSize){
ret= dis.read(bytesArray, bytesRead, (bytesArray.length-bytesRead));
then you write it in one go to the file
bos.write(bytesArray, 0, bytesRead);
For a 100MB file, as you describe, this means that you hold 100MB in memory. This is not... a great idea.
fos= new FileOutputStream(cmrId+"/"+fileName);
InputStream is = sock.getInputStream());
int read = 0;
byte[] buf = new byte[1024];
while( (read = is.read(buf)) != -1) {
fos.write(buf, 0, read);
}
The code above ditches the DataInputStream you are using (which adds nothing as far as I can tell) and reads up to 1024 bytes at a time and writes it in chunks to the FileOutputStream without ever holding more than a kilobyte in memory. Give that a try and see if it is more reliable.
Problem: My File not Launching which is requested from sever.
Okay I have written a server/client application but the problem is when i request for a file from the server it transfer over to the client but what I have notice is that I need to manually refresh the directory to get the file to be in the path or directory. So by saying that, I feel that this is why my code when request the file it doesn't launch.
My approach launching the file from the client after it had just been requested.
Here is my code below:
public static void receiveFile(String fileName) {
try {
int bytesRead;
InputStream in = sock.getInputStream();
DataInputStream clientData = new DataInputStream(in);
fileName = clientData.readUTF();
OutputStream output = new FileOutputStream((fileName));//need to state a repository
long size = clientData.readLong();
byte[] buffer = new byte[1024];
while (size > 0 && (bytesRead = clientData.read(buffer, 0, (int) Math.min(buffer.length, size))) != -1) {
output.write(buffer, 0, bytesRead);
size -= bytesRead;
}
output.close();
in.close();
File file = new File(fileName);
Desktop.getDesktop().open(file);
//System.out.println("File "+fileName+" received from Server.");
} catch (IOException ex) {
//Logger.getLogger(CLIENTConnection.class.getName()).log(Level.SEVERE, null, ex);
ex.printStackTrace();
}
}
Please can you look are tell me what you think I am doing wrong?
Server code:
Try flush the stream before close.
output.flush();
output.close();
I solve it my self the answer is to use the code below:
replace: Desktop.getDesktop().open(file);
with: Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + file);
I have my client server chat
Client sends files and server receives them. But, the problem is that, i don't think that files are received properly because when i check the size of the files i see the difference is halfed for some reasons!
I am using GUI to browse for files in the client side, and then i'm sending a command to the server to know that the client is sending a file. But it is not working
Here is the client and server
public void sendFiles(String file) {
try {
BufferedOutputStream outToClient = null;
outToClient = new BufferedOutputStream(sock.getOutputStream());
System.out.println("Sending file...");
if (outToClient != null) {
File myFile = new File( file );
byte[] mybytearray = new byte[(int) myFile.length()];
FileInputStream fis = null;
fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
this.out.println("SF");
bis.read(mybytearray, 0, mybytearray.length);
outToClient.write(mybytearray, 0, mybytearray.length);
this.out.flush();
outToClient.flush();
outToClient.close();
System.out.println("File sent!");
return;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Server
public void recvFile() {
try {
byte[] aByte = new byte[1];
int bytesRead;
InputStream is = null;
is = sock.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (is != null) {
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
fos = new FileOutputStream("/Users/Documents/Received.png");
bos = new BufferedOutputStream(fos);
bytesRead = is.read(aByte, 0, aByte.length);
do {
baos.write(aByte);
bytesRead = is.read(aByte);
} while (bytesRead != -1);
bos.write(baos.toByteArray());
bos.flush();
bos.close();
// clientSocket.close();
} catch (IOException ex) {
// Do exception handling
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
Can someone help me with this issue? As i don't know how to properly send and receive files
Thank you
You are using two copy techniques, and they are both wrong.
First:
byte[] mybytearray = new byte[(int) myFile.length()];
bis.read(mybytearray, 0, mybytearray.length);
outToClient.write(mybytearray, 0, mybytearray.length);
Here you are assuming:
That the file fits into memory.
That the file length fits into an int.
That read() fills the buffer.
None of these assumptions is valid.
Second:
byte[] aByte = new byte[1];
bytesRead = is.read(aByte, 0, aByte.length);
do {
baos.write(aByte);
bytesRead = is.read(aByte);
} while (bytesRead != -1);
Here you are:
Using a ridiculously small buffer of one byte.
Writing an extra byte if the file length is zero.
Using a do/while where the situation naturally calls for a while (as 99.99% of situations do), and therefore:
Using two read() calls, and only correctly checking the result of one of them.
Pointlessly using a ByteArrayOutputStream, which, as above, assumes the file fits into memory and that its size fits into an int. It also pointlessly adds latency.
Throw them both away and use this, at both ends:
byte[] buffer = new byte[8192];
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
where:
in is a FileInputStream in the case of sending the file, or the socket input stream in the case of receiving the file.
out is a FileOutputStream in the case of receiving the file, or the socket output stream in the case of sending the file
I wrote the following code for downloading some files from a server but the problem is that this code isn't reading the complete response (inputStream). File size is 7.5 MB while I am getting 5.5 MB each time and of course adobe reader complains that file is damaged. Here is the code
import java.net.URLConnection;
public class Downloader {
URL url;
public Downloader(){
try {
url = new URL("https://d396qusza40orc.cloudfront.net/algs4partI/slides%2F13StacksAndQueues.pdf");
FileOutputStream outStream;
ObjectOutputStream oStream;
try {
URLConnection con = url.openConnection();
InputStream inStream = con.getInputStream();
outStream = new FileOutputStream("data.pdf");
oStream = new ObjectOutputStream(outStream);
int bytesRead;
int totalBytesRead = 0;
byte[] buffer = new byte[100000];
while((bytesRead = inStream.read(buffer)) > 0){
//outStream.write(buffer, 0 , bytesRead);
oStream.write(buffer, 0, bytesRead);
buffer = new byte[100000];
totalBytesRead += bytesRead;
}
System.out.println("Total Bytes read are = " + totalBytesRead);
oStream.close();
outStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args){
Downloader d = new Downloader();
}
}
Any ideas what I am doing wrong here? Thanks in advance.
You don't want to be using ObjectOutputStream when you aren't serializing java objects.
Un-comment the line
//outStream.write(buffer, 0 , bytesRead);
and remove
oStream.write(buffer, 0, bytesRead);
So:
while((bytesRead = inStream.read(buffer)) > 0){
outStream.write(buffer, 0 , bytesRead);
buffer = new byte[100000]; // this line is useless
totalBytesRead += bytesRead;
}
Get rid of the ObjectOutputStream altogether. Your file is 5.25 MB (5,511,685 bytes) long, not 7.5 MB.
InputStream that you get from URL connection does not guarantee that all bytes arrive at once. They are transfered over network, so your reading speed may be higher than your network. Method read() returns number of bytes that have been read at current execution of the method. If it returns 0 the information is probably not available at the moment but will be available later.
Method read() returns -1 to indicate end of stream. Bottom line: change > 0 in your if statement to >= 0.
The problem is that you are using ObjectOutputStream. This encodes the output in the Java Object Serialization format, which is not what the PDF reader expects / requires.
Use a plain FileOutputStream and it should work.
I am trying to send a file (an image sent as a byte array) with the client and then the server should receive said byte array to make further use of it. However when I click on the "send" to send the image the file transfer starts (as I get a sentImage.jpg in my Desktop) but it gets stuck for some reason I can't figure out and the image never gets correctly sent.
Here's the part that receives from the server (it already accepted the connection):
public void run(){
try {
byte[] receivedData = new byte[1024];
BufferedInputStream bis = new BufferedInputStream(client.getInputStream());
// while(bis.read() != -1){
s.acquireUninterruptibly();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\Admin\\Desktop\\sentImage.jpg"));
while ((incoming = bis.read(receivedData)) != -1) {
bos.write(receivedData, 0, incoming);
}
s.release();
n.release();
bis.close();
bos.flush();
// }
} catch (IOException e) {
e.printStackTrace();
}
}
and the client is sending here:
public void sendImageResult() {
new Thread(new Runnable() {
public void run() {
try {
int inside = 0;
Socket socket = new Socket("localhost", 4444);
File myImageFile = new File("C:\\Users\\Admin\\Desktop\\test.jpg");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myImageFile));
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream( ));
byte[] byteArray = new byte[1024];
while ((inside = bis.read(byteArray)) != -1){
bos.write(byteArray,0,inside);
}
bis.close();
bos.flush();
} catch (UnknownHostException ex) {
System.out.println("No se pudo establecer la conexión.");
ex.printStackTrace();
} catch (FileNotFoundException fnf){
fnf.printStackTrace();
} catch(IOException ioe){
ioe.printStackTrace();
}
}
}).start();
}
It does not appear that the OutputStream (bos) that is used to write to disk is being closed. This could lead to unexpected results.
As jt said, the OutputStream writing to disk is not being closed, but neither is the OutputStream being used to send the data, nor is the Socket being closed from the sending side. The sending side may be buffering the data at the tcp level, waiting for more bytes before sending the last packet. You are calling flush, but that can be ignored, it's not guaranteed to work like you expect. Another thing to try is calling shutdownOutput on the Socket and seeing if that forces it to flush. You can also try setTcpNoDelay(true) when you open the Socket. If none of that works, get a tcp trace program (I like tcpdump) and use it to see if the packets are actually being sent, it will at least narrow it down to either the send or receive end of things.