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.
Related
Good day.
I am sending a string of user name (so I know the following file belongs to which user) then followed by stream of array of bytes(for audio) from android client to server running in java.
I think of opening different ports but because the server is running in a private network so if I want to open more ports then I need to add more port forwarding function which is quite silly.
I able to send string of username and arrays of bytes separately but when audio file after user name, the audio file will be sped up.
server.java
while (true) {
Socket socket = listener.accept();
try {
InputStream in = socket.getInputStream();
BufferedReader inFileN = new BufferedReader(new InputStreamReader(socket.getInputStream()));
if (fileName==null) {
fileName=inFileN.readLine();
File dir = new File("/home/xxx/Documents/" + fileName);
dir.mkdirs();
}
String filePath = "/home/xxx/Documents/"+fileName+"/voice8K16bitmono.pcm";
FileOutputStream os = null;
byte[] buffer = new byte[1024];
int count;
try {
os = new FileOutputStream(filePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while ((count = in.read(buffer)) > 0)
{
os.write(buffer, 0, count);
}
} finally {
socket.close();
}
client side for writing string of user name
try {
s = new Socket("localhost", 9090);
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.print(userID);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
client side for writing audio file under some condition
try {
s = new Socket("localhost", 9090);
outToServer = s.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
while (isRecording) {
recorder.read(sData, 0, BufferElements2Rec);
detectSilence(sData, threshold);
try {
byte bData[] = short2byte(sData);
//os.write(bData, 0, BufferElements2Rec * BytesPerElement);
outToServer.write(bData, 0, BufferElements2Rec * BytesPerElement);
} catch (IOException e) {
e.printStackTrace();
}
}
Or is there any other better way to use if I want to sending multiple data types from a single client?
ps: I have not implemented multi-threaded server at this point because I want to make sure it works with a single user first
Thank you.
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 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.
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 am sending files to remote Android client from java server. I write the bytes using outputstream. On reading these bytes read() method keep trying to read bytes after the stream is ended. if I close the outputstream on server-side, read operation work fines. But I have to write file on the same socket again so can't close output stream any solution?
NOTE: MY CODE WORKS FINE FOR SHARING SINGLE FILE
CODE FOR WRITING FILE
public static void writefile(String IP, String filepath, int port, OutputStream out) throws IOException {
ByteFileConversion bfc = new ByteFileConversion();
byte[] file = bfc.FileToByteConversion(filepath);
out.write(file, 0, file.length);
out.close(); // i donot want to close this and how can I tell reading side that stream is ended.
System.out.println("WRITTEN");
}
Here Am I reading the file on Android :
public Bitmap fileReceived(InputStream is) {
Bitmap bitmap = null;
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = "a.png";
String imageInSD = baseDir + File.separator + fileName;
// System.out.println(imageInSD);
if (is != null) {
FileOutputStream fos = null;
OutputStream bos = null;
try {
bos = new FileOutputStream(imageInSD);
byte[] aByte = new byte[1024];
int bytesRead;
int index = 0;
DataInputStream dis = new DataInputStream(is);
while ((bytesRead = is.read(aByte)) > 0) {
index = bytesRead + index;
bos.write(aByte, 0, bytesRead);
// index = index+ bytesRead;
System.out.println("Loop" + aByte + " byte read are " + bytesRead + "whree index =" + index);
}
bos.flush();
bos.close();
Log.i("IMSERVICE", "out of loop");
java.io.FileInputStream in = new FileInputStream(imageInSD);
bitmap = BitmapFactory.decodeStream(in);
bitmap = BitmapFactory.decodeFile(imageInSD);
Log.i("IMSERVICE", "saved");
// if (bitmap != null)
// System.out.println("bitmap is "+ bitmap.toString());
} catch (IOException ex) {
// Do exception handling
// Log.i("IMSERVICE", "exception ");
System.out.println("ex");
}
}
return bitmap;
}
Actually, I want to reset socket connection
Thanks in advance
You need to:
Send the length of the file ahead of the file. You can use DataOutputStream.writeLong() for that, and DataInputStream.readLong() at the receiver.
Read exactly that many bytes from the stream at the receiver:
while (total < length && (count = in.read(buffer, 0, length-total > buffer.length ? buffer.length : (int)(length-total))) > 0)
{
out.write(buffer, 0, count);
total += count;
}
E&OE
Actually I want to reset socket connection
Actually you don't want to do any such thing.
If i donot close outputstream the read operation on other side stuck on keep reading
That is because the client socket's InputStream is still waiting for the server to send some packets of data thus blocking your Main Thread.
Solution:
You can put each of your sending(OutputStream) and reading(InputStream) of packets of data from the socket to a Thread to prevent blocking your main thread when reading and sending.
Create a thread that reads the InputStream and another one for the OutputStream
Side note:
Don't try to close your outputStream that it cant be reopened again as the documentation is saying:
Closing the returned OutputStream will close the associated socket.
The general contract of close is that it closes the output stream. A closed stream cannot perform output operations and cannot be reopened.