I am sending a file over socket from client to server. Thats working fine. But once a file is received, server program is not receiving any further messages. Its all receiving is null.
Here is the client-server code.
Client:
main(...){
Socket sock = new Socket("127.0.0.1", 12345);
File file = new File("file.txt");
byte[] mybytearray = new byte[(int) file.length()];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
bis.read(mybytearray, 0, mybytearray.length);
OutputStream os = sock.getOutputStream();
os.write(mybytearray, 0, mybytearray.length);
PrintWriter out = new PrintWriter(os, true);
out.println("next message");
//closing here all streams and socket
}
Server:
main(...){
ServerSocket servsock = new ServerSocket(12345);
while (true) {
Socket sock = servsock.accept();
byte[] mybytearray = new byte[1024];
InputStream is = sock.getInputStream();
Scanner scan1 = new Scanner(is);
FileOutputStream fos = new FileOutputStream("myfile.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(mybytearray, 0, mybytearray.length);
bos.write(mybytearray, 0, bytesRead);
bos.close();
fos.close();
//Till here works fine, and file is successfully received.
//Below is the code to receive next message.
//Unfortunately it is not working
BufferedReader input = new BufferedReader(new InputStreamReader(is));
String line = input.readLine();
System.out.println(line); //prints null, Whats the reason?
}
}
This is an example that assumes it is a file then a line of text. In both cases I send the length first so it can just be dealt with as byte arrays.
Server:
ServerSocket servsock = new ServerSocket(12345);
while (true) {
Socket sock = servsock.accept();
try (DataInputStream dis = new DataInputStream(sock.getInputStream())) {
int len = dis.readInt();
byte[] mybytearray = new byte[len];
dis.readFully(mybytearray);
try (FileOutputStream fos = new FileOutputStream("myfile.txt")) {
fos.write(mybytearray);
}
len = dis.readInt();
mybytearray = new byte[len];
dis.readFully(mybytearray);
String line = new String(mybytearray);
System.out.println("line = " + line);
}
}
Client:
Socket sock = new Socket("127.0.0.1", 12345);
File file = new File("file.txt");
byte[] mybytearray = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(mybytearray);
try(DataOutputStream os = new DataOutputStream(sock.getOutputStream())) {
os.writeInt(mybytearray.length);
os.write(mybytearray, 0, mybytearray.length);
String nextMessage = "next message\n";
byte message[] = nextMessage.getBytes();
os.writeInt(message.length);
os.write(message, 0, message.length);
}
The basic problem is you assume a) your file is exactly 1024 bytes long when you read. b) when you attempt to read you get all the data in one go. The minimum is 1 byte even if you wrote much more.
I suggest you
send the length with the file so you know how much to read.
you chose either binary or text and only do one or the other.
Related
The code I have posted below works for single file transfer over a socket. But it doesn't work for multiple file transfers over a socket. When trying multiple file transfers over the socket the code crashes.
I send multiple files by looping over the server sending code x amount of times, and run the receiving code x amount of times. When trying to send multiple files, the first file will send successfully, the second file name and size will be read successfully but the error in my code happens after this.
In my receiving client I tried to use to suggestion posted here: Java multiple file transfer over socket but had no success.
The error is on the client side.
The question I am asking is: Why isn't this code working for multiple files, and how can I fix it?
Server Sending
try{
byte[] bytes = new byte[(int)file.length()];
FileInputStream fis = new FileInputStream(file);
OutputStream os = socket.getOutputStream();
out.println(file.getName()); // Send Filename
out.println(file.length()); // Send filesize
int count;
while ((count = fis.read(bytes)) > 0) {
os.write(bytes, 0, count);
}
os.flush();
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
Client Recieving
try{
String file = in.readLine(); // Read filename
int fileSize = Integer.parseInt(in.readLine()); // Read Filesize
//ERROR HAPPENING ON LINE ABOVE IN LOOPS AFTER THE FIRST
byte [] buf = new byte [fileSize];
FileOutputStream fos = new FileOutputStream(file);
InputStream is = socket.getInputStream();
int count = 0;
while (fileSize > 0 && (count = is.read(buf, 0, (int)Math.min(buf.length, fileSize))) != -1){
fos.write(buf, 0, count);
fileSize -= count;
}
fos.close();
}catch(IOException e){
e.printStackTrace();
}
The error is a NumberFormatException, on loops after the first when the client is receiving part of a file for the input to the fileSize.
Make sure you flush the PrintWriter before you then write raw bytes directly to the OutputStream that the PrintWriter is attached to. Otherwise, you could write any buffer data out of order to the underlying socket.
But more importantly, make sure that if you use buffered reading on the receiving end that you read the file bytes using the same buffer that receives the file name and file size. You should also transfer the File using smaller fixed chunks, don't allocate a single byte[] array for the entire file size, that is a waste of memory for large files, and likely to fail.
Server:
try{
byte[] bytes = new byte[1024];
FileInputStream fis = new FileInputStream(file);
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
PrinterWriter pw = new PrintWriter(bos);
pw.println(file.getName()); // Send Filename
pw.println(file.length()); // Send filesize
pw.flush();
int count;
while ((count = fis.read(bytes)) > 0) {
bos.write(bytes, 0, count);
}
bos.flush();
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
Client:
try{
byte [] buf = new byte [1024];
FileOutputStream fos = new FileOutputStream(file);
InputStream is = socket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
InputStreamReader isr = new InputStreamReader(bis);
String file = isr.readLine(); // Read filename
long fileSize = Long.parseLong(isr.readLine()); // Read Filesize
int count = 0;
while ((fileSize > 0) && (count = bis.read(buf, 0, (int)Math.min(buf.length, fileSize))) > 0){
fos.write(buf, 0, count);
fileSize -= count;
}
fos.close();
}catch(IOException e){
e.printStackTrace();
}
That being said, you might also consider using DataOutputStream.writeLong() and DataInputStream.readLong() to send/receive the file size in its original binary format instead of as a textual string:
Server:
try{
byte[] bytes = new byte[1024];
FileInputStream fis = new FileInputStream(file);
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
PrinterWriter pw = new PrintWriter(bos);
pw.println(file.getName()); // Send Filename
pw.flush();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeLong(file.length()); // Send filesize
dos.flush();
int count;
while ((count = fis.read(bytes)) > 0) {
bos.write(bytes, 0, count);
}
bos.flush();
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
Client:
try{
byte [] buf = new byte [1024];
FileOutputStream fos = new FileOutputStream(file);
InputStream is = socket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
InputStreamReader isr = new InputStreamReader(bis);
String file = isr.readLine(); // Read filename
DataInputStream dis = new DataInputStream(bos);
long fileSize = dis.readLong(); // Read Filesize
int count = 0;
while ((fileSize > 0) && (count = bis.read(buf, 0, (int)Math.min(buf.length, fileSize))) > 0){
fos.write(buf, 0, count);
fileSize -= count;
}
fos.close();
}catch(IOException e){
e.printStackTrace();
}
I am currently working on a File Transfer Client and Server program. I can request and receive one file but then when I try to request another, it doesn't work. It gives me an IOException.
Process: Client prompts user to input a name, sends to server, server responds with file, and server should wait for another request while client prompts again for user to input a name.
I believe I'm not "Waiting" correctly on the server side. Any help that would kick me into the right direction would help.
Client Code:
BufferedReader consoleIn = new BufferedReader(new InputStreamReader(System.in));
System.out.print("What file do you want? ");
name = consoleIn.readLine();
int bytesRead;
if(!name.equals("!")) {
InputStream in = null;
OutputStream output = null;
DataInputStream serverData = null;
while(!name.equals("!")) {
//fileOut = new PrintWriter(new FileOutputStream(name));
socketOut.println(name);
socketOut.flush();
try {
in = socket.getInputStream();
} catch (IOException ex) {
System.out.println("Can't get socket input stream. ");
}
serverData = new DataInputStream(in);
String fileName = serverData.readUTF();
output = new FileOutputStream(fileName);
long size = serverData.readLong();
byte[] buffer = new byte[4000];
while (size > 0 && (bytesRead = serverData.read(buffer, 0, (int)Math.min(buffer.length, size))) != -1)
{
output.write(buffer, 0, bytesRead);
size -= bytesRead;
}
System.out.print("What file do you want? ");
name = consoleIn.readLine();
}
}
Server Code:
socket = serverSocket.accept();
System.out.println("Connection accepted!");
BufferedReader socketIn =
new BufferedReader(new InputStreamReader(socket.getInputStream()));
//PrintWriter socketOut = new PrintWriter(socket.getOutputStream());
String name;
BufferedReader fileIn;
String line;
name = socketIn.readLine();
System.out.println(name);
while((!name.equals("!")) && (!name.equals("*"))) {
File file = new File(rootDirectory, name);
byte[] bytes = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
dis.readFully(bytes, 0, bytes.length);
OutputStream os = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF(file.getName());
dos.writeLong(bytes.length);
dos.write(bytes, 0, bytes.length);
dos.flush();
System.out.println("Sending: " + name);
os.write(bytes, 0, bytes.length);
os.flush();
name = socketIn.readLine();
System.out.println(name);
}
From the javadocs for Socket.getInputStream():
Closing the returned InputStream will close the associated socket.
So the client's in and serverData streams should be closed outside the loop.
Additional comments:
There is no need to wrap the while (!name.equals("!")) in if(!name.equals("!"))
Closing the DataInputStream will close the underlying InputStream
Edit:
There is also a bug in the server. It sends the file twice:
dos.write(bytes, 0, bytes.length);
// ...
os.write(bytes, 0, bytes.length);
I'm trying to send my image from android client to Java server. Size of image that i'm sending is about 99kb, but server always reads a few kb less, sometimes 98, sometimes 96 and so on. I'd like to know why that data is lost and how can I send image in a proper way. Please help :)
Code:
Client(sending image):
public void sendImage(File file){
try {
out = new PrintWriter(socket.getOutputStream(),true);
out.println("Image");
out.println(file.length());
byte[] byteArray = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(byteArray,0,byteArray.length);
OutputStream os = socket.getOutputStream();
FilterOutputStream bos = new FilterOutputStream(os);
bos.write(byteArray,0,byteArray.length);
bos.flush();
os.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Server(receiving image):
if(input.equals("Image")){
input = in.readLine();
int fileSize = Integer.parseInt(input);
System.out.println("FILESIZE:" +fileSize);
byte[] byteArray = new byte[fileSize];
FileOutputStream fileOutputStream =
new FileOutputStream("filename.jpg");
BufferedOutputStream bos =
new BufferedOutputStream(fileOutputStream);
BufferedInputStream bis = new BufferedInputStream(in_);
int bytesRead = bis.read(byteArray, 0, byteArray.length);
int current = bytesRead;
do {
bytesRead = bis.read(byteArray, current,
(byteArray.length - current));
if (bytesRead >= 0) {
current += bytesRead;
System.out.println(current);
}
} while (bytesRead != -1);
bos.write(byteArray, 0, current);
bos.flush();
bos.close();
}
EDIT
Problem solved, working code is as follows:
Client side:
public void sendImage(File file){
try {
DataOutputStream out = new DataOutputStream(
socket.getOutputStream());
out.writeChar('I');
DataInputStream dis = new DataInputStream(new FileInputStream(file));
ByteArrayOutputStream ao = new ByteArrayOutputStream();
int read = 0;
byte[] buf = new byte[1024];
while ((read = dis.read(buf)) > -1) {
ao.write(buf, 0, read);
}
out.writeLong(ao.size());
out.write(ao.toByteArray());
out.flush();
out.close();
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Server side:
if(input =='I'){
DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
long length = dis.readLong();
File to = new File("filename.jpg");
DataOutputStream dos = new DataOutputStream(
new FileOutputStream(to));
byte[] buffer = new byte[1024];
int len, current = 0;
System.out.println(length);
while ( current != length) {
len = dis.read(buffer);
dos.write(buffer, 0, len);
current += len;
System.out.println(current);
}
dis.close();
dos.close();
}
From my personal experience PrintWriter and Buffers dont work well together..
As buffers trying to read data before you tell it to it can "steal" data that it should not do. For example if you use any kind of buffered reader to read the input on the server side that buffer will steal some parts at the "start" of the incomming image becuase it think's it's just another line. You could always try using DataInputStream and DataOutputStream instead..
Client:
public void sendImage(File file) {
try {
DataOutputStream out = new DataOutputStream(
socket.getOutputStream());
out.writeChar('I'); // as image,
DataInputStream dis = new DataInputStream(new FileInputStream(file));
ByteArrayOutputStream ao = new ByteArrayOutputStream();
int read = 0;
byte[] buf = new byte[1024];
while ((read = dis.read(buf)) > -1) {
ao.write(buf, 0, read);
}
out.writeLong(ao.size());
out.write(ao.toByteArray());
out.flush();
out.close();
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Server:
// assuming folder structure exists.
public void readImage(Socket s, File to) throws IOException {
DataInputStream dis = new DataInputStream(s.getInputStream());
char c = dis.readChar();
if (c == 'I') {
long length = dis.readLong();
DataOutputStream dos = new DataOutputStream(
new FileOutputStream(to));
byte[] buffer = new byte[1024];
int len;
while ((len = dis.read(buffer)) != -1) {
dos.write(buffer, 0, len);
}
dis.close();
dos.close();
}
}
As a starting point, in the client side, you will also need a loop for reading the local image, because are you sure that...
bis.read(byteArray,0,byteArray.length);
... is really reading the whole image? So you will also need a loop as in the server side.
I'm trying to download a file from PC to Android device (emulator or physical)
Everything goes fine for small and medium sized files, but when I try to send something larger than say 10Mb, server never reaches this statement out2.println("ready");, hence the client hangs waiting for "ready" from server
Seems that server stucks at this: os.write(bytearray, 0, bytearray.length);
So far I've tried this on emulator, I'm going to report about results on a real device shortly
Here is my client part, in Android app: Android client sends "download" string to server, then receives "ready" reply from it, and starts reading file from InputStream
int filesize = 2022386;
int bytesRead;
int currentTot = 0;
Socket socket1 = new Socket("172.16.6.119", 50001); //data line
Socket socket2 = new Socket("172.16.6.119", 50001); //control line
BufferedReader in2 = new BufferedReader(new InputStreamReader(socket2.getInputStream()));
PrintWriter out2 = new PrintWriter(socket2.getOutputStream(), true);
out2.println("download:"); //control line
String usrtxt = in2.readLine();
if(usrtxt.substring(0,5).equals("ready")) //control line
{
byte [] bytearray = new byte [filesize];
InputStream is = socket1.getInputStream(); //data line
FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory().toString() + "/sunset.jpg");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(bytearray,0,bytearray.length);
currentTot = bytesRead;
Log.e("DOWNLOAD", "init value: bytesread = " + Integer.toString(bytesRead));
do {
bytesRead =
is.read(bytearray, currentTot, (bytearray.length-currentTot)); //<--does not pull data (WHY?)
Log.e("DOWNLOAD", "bytesread = " + Integer.toString(bytesRead));
if(bytesRead >= 0) currentTot += bytesRead;
} while(bytesRead > -1);
out1.println("finished:");
bos.write(bytearray, 0 , currentTot);
Log.e("DOWNLOAD", Integer.toString(currentTot));
bos.flush();
bos.close();
socket1.close(); socket2.close();
}
And this is my server code: it accepts connection from client, then receives "download" string from it, replies with "ready", and puts the file onto OutputStream
while (true) {
final Socket socket = serverSocket.accept(); //data line
final Socket socket2= serverSocket.accept(); //control line
BufferedReader in2 = new BufferedReader(new InputStreamReader(socket2.getInputStream()));
PrintWriter out2 = new PrintWriter(socket2.getOutputStream(), true);
String usrtxt = in2.readLine(); //control line
if(usrtxt.substring(0,8).equals("download"))
{
System.out.println("accepted download request. sending file");
File transferFile = new File("sunset.jpg");
byte[] bytearray = new byte[(int)transferFile.length()];
FileInputStream fin = new FileInputStream(transferFile);
BufferedInputStream bin = new BufferedInputStream(fin);
bin.read(bytearray, 0, bytearray.length);
OutputStream os = socket.getOutputStream();
os.write(bytearray, 0, bytearray.length); //data line
os.flush();
os.close();
out2.println("ready"); //control line
socket.close(); socket2.close();
bin.close(); fin.close();
System.out.println("file transfer complete");
}//end if
}//end while
This is no way to copy streams. It assumes too many things that may not be true.
The canonical way in Java is as follows:
byte[] buffer = new byte[8192]; // or whatever you like, anything above zero. Note that it doesn't have to be the size of the file
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
If you know the length in advance and you want to keep the socket open afterwards, keep track of the bytes transferred so far via 'total += count;' after the read call inside the loop, and change the read call to read(buffer, 0, length-total > buffer.length ? buffer.length : (int)(length-total)).
I am trying to send a file from one computer to another using Java. I have written the code below, it works fine if both sender and receiver are started in the same computer but if they work on different machines received file size is bigger than the original file and it is corrupted.
Note: I am trying to transfer files which are max 10 MBs.
How can I fix this?
Sender:
ServerSocket server_socket = new ServerSocket(8989);
File myFile = new File(myPath);
Socket socket = server_socket.accept();
int count;
byte[] buffer = new byte[1024];
OutputStream out = socket.getOutputStream();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(myFile));
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
out.flush();
}
socket.close();
Receiver:
Socket socket = new Socket(address, 8989);
FileOutputStream fos = new FileOutputStream(anotherPath);
BufferedOutputStream out = new BufferedOutputStream(fos);
byte[] buffer = new byte[1024];
int count;
InputStream in = socket.getInputStream();
while((count=in.read(buffer)) >0){
fos.write(buffer);
}
fos.close();
socket.close();
On the client side you write up to count bytes and send them:
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
on the server side you read up to count bytes - but then you write the whole buffer to file!
while((count=in.read(buffer)) > 0){
fos.write(buffer);
Just change it to:
fos.write(buffer, 0, count);
and you'll be on the safe side. BTW your program has another small bug: read() can return 0 which doesn't mean InputStream ended. Use >= instead:
count = in.read(buffer)) >= 0
Have you considered IOUtils.copy(InputStream, OutputStream) from Apache Commons? It would reduce your whole while loops to:
OutputStream out = socket.getOutputStream();
InputStream in = new FileInputStream(myFile);
IOUtils.copy(in, out);
socket.close();
Less code to write, less code to test. And buffering is done internally.
Remember that in.read(buffer) not necessarily fills up the whole buffer with new data. Therefore you should make sure you don't write the whole buffer. Change
while((count=in.read(buffer)) >0){
fos.write(buffer);
}
to
while((count=in.read(buffer)) >0){
fos.write(buffer, 0, count);
}
sender
Socket sock = new Socket("127.0.0.1", 5991);
System.out.println("Connecting.........");
File myFile = new File("/root/qrcode/");
File[] files = myFile.listFiles();
OutputStream os = sock.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
DataOutputStream dos = new DataOutputStream(bos);
dos.writeInt(files.length);
long totalBytesRead = 0;
int percentCompleted = 0;
for(File file : files)
{
long length = file.length();
dos.writeLong(length);
String name = file.getName();
dos.writeUTF(name);
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
int theByte = 0;
while((theByte = bis.read()) != -1)
{
totalBytesRead += theByte;
bos.write(theByte);
}
// System.out.println("file read");
bis.close();
}
dos.close();
//Closing socket
sock.close();
receiver
ServerSocket serverSocket = new ServerSocket(5991);
while(true) {
Socket clientSocket = null;
System.out.println("Starting...");
clientSocket = serverSocket.accept();
InputStream in = clientSocket.getInputStream(); //used
BufferedInputStream bis = new BufferedInputStream(in);
String dirPath ;
dirPath = "/root/NewFolder";
try{
DataInputStream dis = new DataInputStream(bis);
int filesCount = dis.readInt();
File[] files = new File[filesCount];
long f_l = 0;
int count =0 ;
long totalBytesRead = 0;
int percentCompleted = 0;
for(int i = 0; i < filesCount; i++)
{
long fileLength = dis.readLong();
String fileName = dis.readUTF();
f_l = f_l +fileLength;
files[i] = new File(dirPath + "/" + fileName);
FileOutputStream fos = new FileOutputStream(files[i]);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int tot = 0;
for(int j = 0; j < fileLength; j++) {
bos.write(bis.read());
}
bos.close();
}
}catch(Exception ex)
{
System.out.println("error in socket programming ");
}
}