i'm doing a server with Java and a client with Android. Everything works fine, but when i try to receive the file on Android, the IO input freezes. I tried to do the same with a Java test app, and works fine.
My code on the client side:
int bytesRead;
long current = 0;
byte [] mybytearray = new byte[InfoPrograma.BUFFER_LENGTH];
//Receive file
InputStream is = socket.getInputStream();
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(file)
);
while (
(bytesRead = is.read(
mybytearray,
0,
mybytearray.length
)
) >= 0) {
current += bytesRead;
bos.write(mybytearray, 0 , bytesRead);
}
bos.flush();
bos.close();
The server side code:
File file = new File(fileStr);
byte[] buffer = new byte[InfoPrograma.BUFFER_LENGTH];
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(file)
);
OutputStream os = socket.getOutputStream();
long tmp = 0;
while ((count = bis.read(buffer)) > 0) {
os.write(buffer, 0, count);
tmp += count;
System.out.println(tmp);
}
os.flush();
BUFFER_LENGHT is 2000. If you need anything else, ask for it, please.
Thank you.
Done it. The only way i found is to send first the lenght of the file to the client, save it, and then do read() while (on my code) current < fileLength.
Related
I'm trying to build a file server and file client program in Java using sockets, and I've been running into some issues when trying to send files from the server to the client. Below is the code that I use to send and receive files respectively:
private void sendFile(String filePath) {
try (BufferedInputStream fileInputStream = new BufferedInputStream(new FileInputStream(filePath))) {
BufferedOutputStream outputStream = new BufferedOutputStream(socket.getOutputStream());
byte[] buffer = new byte[4096];
while (fileInputStream.read(buffer) != -1) {
outputStream.write(buffer);
outputStream.flush();
}
}
catch (IOException e) {e.printStackTrace();}
}
private void downloadFile(String fileName, long fileSize) {
try (BufferedOutputStream fileOutputStream = new BufferedOutputStream(new FileOutputStream(downloadDir + "/" + fileName));
BufferedInputStream inputStream = new BufferedInputStream(socket.getInputStream());
OutputStreamWriter writer = new OutputStreamWriter(new BufferedOutputStream(socket.getOutputStream()), "UTF-8");) {
writer.write("GET" + fileName + System.lineSeparator());
writer.flush();
long totalReceived = 0;
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
while (totalReceived < fileSize) {
inputStream.read(buffer);
int numOfBytesToWrite = fileSize - totalReceived > bufferSize ? buffer.length : (int)(fileSize % bufferSize);
fileOutputStream.write(buffer, 0, numOfBytesToWrite);
fileOutputStream.flush();
totalReceived += numOfBytesToWrite;
}
}
catch (IOException e) {}
}
The downloaded file does get created and seems to be of the right size, but always gets corrupted and cannot be opened by any program. However, this issue does not show itself when I run the client on the same machine and connect it to "localhost" or "127.0.0.1", then there are no problems and downloaded files are not corrupted. See any issues with my code?
In your sendFile() you need to consider the return value from the read() which may be less than 4096... This value should then be used in the write call to only write out the portion of the array that has been populated...
int bytesRead = 0;
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
outputStream.flush();
}
A similar problem occurs in downloadFile(), return from read() is the actual number of bytes read, some value less than or equal to 4096...
long totalReceived = 0;
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
while (totalReceived < fileSize) {
int bytesRead = inputStream.read(buffer);
fileOutputStream.write(buffer, 0, bytesRead);
fileOutputStream.flush();
totalReceived += bytesRead;
}
Why does your code work on localhost, but not over a network?
Atypical physical layer of a network is Ethernet, this will have a MTU of 1500 bytes. So you'll probably be seeing successive read() calls only filling 1500, or fewer bytes of your buffer...
However, localhost is optimized in the stack to bypass the physical layer which will not have this limitation. It is likely in this case successive calls will fill the full 4096 buffer, apart from the last, unless your file size is exact multiple of 4096.
I made a server that sends a text file to the client (Android) and I'm only getting the file when I'm getting connection timed out.
Why the "connection timed out" is happening in the first place? and also, it takes like 1 minute to the file to be received (1MB).
Server:
FileInputStream fis = new FileInputStream(
new File("123.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
byte[] mybytearray = new byte[8192];
OutputStream os;
try {
os = clientSocket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
int read;
while ((read = dis.read(mybytearray)) > 0) {
dos.write(mybytearray, 0, read);
}
} catch (IOException e) {
e.printStackTrace();
}
Client:
InputStream in;
int Size = 0;
try {
Size = clientSocket.getReceiveBufferSize();
in = clientSocket.getInputStream();
DataInputStream dis = new DataInputStream(in);
byte[] buffer = new byte[Size];
int read;
while ((read = dis.read(buffer)) > 0) {
fos.write(buffer, 0, read);
}
} catch (IOException e) {
e.printStackTrace();
}
Any idea how to fix this problem?
You don't close stream on the server side. So nobody knows that this is the end of stream and wait continues till time out. Add close() like this:
os = clientSocket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
int read;
while ((read = dis.read(mybytearray)) > 0) {
dos.write(mybytearray, 0, read);
}
os.close();
Also, on client side you should expect zero input. Its is OK for slow connection. Only -1 means that connection is closed. Change code like this:
while ((read = dis.read(buffer)) > -1)
I have two files: a chat server and a chat client. The chat client is supposed to say that it wants to upload a file to the server. And then it uploads. However, right now, all of the messages are being sent / received properly, but when I try to get the file transfer, the only thing I get is a file with 0 bytes (which is at the path I specify inside of the server class.
Broken part of the chatclient class:
/**
* Sends a broadcast to the server
*/
public static void broadcast() throws IOException {
if (UserInput.getText() == "/upload") {
File myFile = new File (FILE_TO_SEND);
byte [] mybytearray = new byte [(int)myFile.length()];
fis = new FileInputStream(myFile);
bis = new BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
os = Socket.getOutputStream();
System.out.println("Sending " + FILE_TO_SEND + "(" + mybytearray.length + " bytes)");
os.write(mybytearray,0,mybytearray.length);
os.flush();
System.out.println("Done.");
}
System.out.println("" + UserInput.getText());
outputStream.println(UserInput.getText());
outputStream.flush();
}
Broken part of the server class:
if (input.contains("/upload")) {
byte [] mybytearray = new byte [FILE_SIZE];
InputStream is = csocket.getInputStream();
fos = new FileOutputStream(FILE_TO_RECEIVED);
bos = new BufferedOutputStream(fos);
bytesRead = is.read(mybytearray,0,mybytearray.length);
current = bytesRead;
do {
bytesRead = is.read(mybytearray, current, (mybytearray.length-current));
if (bytesRead >= 0) current += bytesRead;
}
while(bytesRead > -1);
bos.write(mybytearray, 0 , current);
bos.flush();
System.out.println("File " + FILE_TO_RECEIVED + " downloaded (" + current + " bytes read)");
}
Your copy loop is nonsense. The canonical way to copy a stream in Java is as follows:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
where 'count' is an int, and 'buffer' is a byte[] array of length > 0. I usually use 8192.
You should try surrounding the broken code with try-catch block and print out the error message from the stack. this would give you a better idea of what is not working. It's not a solution, I know, but it's easier to find a solution if you know the exact problem.
i want to send the file size and one other integer, the tabelet serial number from and android tablet to a server running windows 7:
what is wrong with my client code and how to make the server accept the to different byte streams of data?
client code of android tablet
try {
byte[] bytes = new byte[(int) length];
fis = new FileInputStream(file2);
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(socket.getOutputStream());
int count;
// convert integer to byte
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(1992);
byte[] preByte = baos.toByteArray();
// the first byte that sends the tablet serial number and the size of the next file it is going to send
bis.read(preByte);
// the next sent is the file itself which is a database file
while ((count = bis.read(bytes)) > 0) {
bos.write(bytes, 0, count);
}
fis.close();
bis.close();
fis = null;
bis = null;
socket.close();
server code that will receive the two files
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
System.out.println("streams are setup from new thread\n");
is = socket.getInputStream();
bufferSize = socket.getReceiveBufferSize();
buffer = new byte[bufferSize];
while ((count = is.read(buffer)) > 0) {
bos.write(buffer, 0, count);
} // end while
bos.flush();
bos.close();
is.close();
try this
dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
dos.writeLong(length);
dos.writeInt(1992);
for (int b; (b = bis.read()) != -1;) {
dos.write(b);
}
...
dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
long length = dis.readLong();
int serialNumber = dis.readInt();
... read bytes
It seems that you are reading into preByte array instead of writing it to the output stream:
bis.read(preByte);
You probably meant:
bos.write(preByte);
You don't need the ByteArrayOutputStream at all. Just wrap a DataOutputStream around the BufferedOutputStream, and do all the writes via the DataOutputStream.
I have a program that updates files on the computer using information sent by a server, using sockets. The way I had it worked, but i wanted to make it more intuitive, simpler, more reliable, etc. here is the previous code:
int filesize = 6022386; // filesize temporary hardcoded
int bytesRead;
int current = 0;
/**
* receive file
*/
try {
byte[] byteArray = new byte[filesize];
java.io.InputStream inStream = socket.getInputStream();
bytesRead = inStream.read(byteArray, 0, byteArray.length);
FileOutputStream fileOutStream = new FileOutputStream(
"C:\\Program Files\\AVTECH\\NPS\\Files\\bin\\NPS Game.txt");
BufferedOutputStream buffOutStream = new BufferedOutputStream(
fileOutStream);
current = bytesRead;
do {
bytesRead = inStream.read(byteArray, current,
(byteArray.length - current));
if (bytesRead >= 0)
current += bytesRead;
} while (bytesRead > -1);
buffOutStream.write(byteArray, 0, current);
buffOutStream.flush();
buffOutStream.close();
inStream.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
socket.close();
}
as you can see, in the do, while loop, it is using the input stream to get the data. now that i've updated my program, i have the stream sending an object called UpdateObject, which holds the byte[] array along with the file directory. here is that code:
int filesize = 6022386; // filesize temporary hardcoded
int bytesRead;
int current = 0;
try {
byte[] byteArray = o.getFile();
java.io.InputStream inStream = socket.getInputStream();
bytesRead = inStream.read(byteArray, 0, byteArray.length);
FileOutputStream fileOutStream = new FileOutputStream(o.getPath());
BufferedOutputStream buffOutStream = new BufferedOutputStream(
fileOutStream);
current = bytesRead;
do {
bytesRead = inStream.read(byteArray, current,
(byteArray.length - current));
if (bytesRead >= 0)
current += bytesRead;
} while (bytesRead > -1);
buffOutStream.write(byteArray, 0, current);
buffOutStream.flush();
buffOutStream.close();
inStream.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
now my question is this: how do i change it so instead of using the instream, to use just a byte[] object in the UpdateObject sent over the socket? i've done some google searching, but i dont feel like i know the right question to ask. any help would be great! thanks in advance!!!
By replacing most of your code inside the try catch block with:
FileOutputStream fileOutStream = new FileOutputStream(
UpdateObject.getDirectory()+"\\NPS Game.txt");
fileOutStream.write(UpdateObject.getBytes()); //this is the byte[] array
fileOutStream.close();
Hope this helps.