error in transferring file using tcp in java - java

I am developing a web app using jsp in which i use a tcp connection to send a file from server to a client. But while doing so, the program goes into an infinite loop.
It doesn't return anything. Can anyone please help me?
I am posting the server and client code here.
Server code:
byte[] sendData = new byte[1024];
byte[] receiveData = new byte[1024];
sendData = "FILE".getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 5006);
clientSocket.send(sendPacket);
sendData = file.getBytes();
sendPacket = new DatagramPacket(sendData, sendData.length, IPAddress, 5006);
clientSocket.send(sendPacket);
ServerSocket serverSocket = new ServerSocket(5494);
Socket socket = serverSocket.accept();
File transferFile = new File("C:\\Users\\Krishna\\Documents\\LanMan\\" + file);
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);
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
clientSocket.receive(receivePacket);
String a = (new String(receiveData, "UTF-8")).trim();
//if(a.equals())
os.flush();
//bin.close();
socket.close();
serverSocket.close();
Client code:
if (a.startsWith("FILE")) {
byte b[] = new byte[1024];
received = new DatagramPacket(receiveData, receiveData.length);
serversocket.receive(received);
a = (new String(receiveData, "UTF-8")).trim();
int filesize = 2022386;
int bytesRead;
int currentTot = 0;
socket = new Socket(ip, 5494);
byte[] bytearray = new byte[filesize];
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream("C:\\LanMan\\" + a);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(bytearray, 0, bytearray.length);
currentTot = bytesRead;
do {
bytesRead = is.read(bytearray, currentTot, (bytearray.length - currentTot));
if (bytesRead >= 0) currentTot += bytesRead;
} while (bytesRead > -1);
bos.write(bytearray, 0, currentTot);
bos.flush();
bos.close();
//fos.close();
//is.close();
sendData = "OK".getBytes();
DatagramPacket send = new DatagramPacket(sendData, sendData.length, ip, port);
serversocket.send(send);
socket.close();
}

You implemented a deadlock.
The server writes the file content, then wait for a datagram packet from the client, the closes the socket.
The client reads until the server closes the socket, then sends a datagram packet.
So each party is waiting for the other one.
Also, never ignore the result of the InputStream.read() method like you're doing in the server code. You can never assume that all the file will be read in one single call.

Related

CipherOutputStream not working

I have a problem with the following code.
If I use the ObjectOutputStream everything runs fine but when I try to use the CipherOutputStream I get the following error in the server side.
If I send one file I don't receive it fully.
If I send more than one file the last one to be sended is not received fully but the previous are.
What could it be?
I have seen other posts but they didn't help me.
java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at java.io.BufferedOutputStream.write(BufferedOutputStream.java:128)
at myCloudServer$myCloudServerThread.run(myCloudServer.java:257)
Client code. Sending a file.
SocketFactory socketFactory = SSLSocketFactory.getDefault();
clientSocket = socketFactory.createSocket(serverAddress[0], Integer.parseInt(serverAddress[1]));
ObjectInputStream objectInputStream = new ObjectInputStream(clientSocket.getInputStream());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(clientSocket.getOutputStream());
[...]
byte[] buffer = new byte[1024];
objectOutputStream.writeObject(sendingClientFiles.size());
for (File sendingClientFile : sendingClientFiles) {
[...]
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
SecretKey secretKeyEncrypt = keyGenerator.generateKey();
Cipher cipherEncrypt = Cipher.getInstance("AES");
cipherEncrypt.init(Cipher.ENCRYPT_MODE, secretKeyEncrypt);
CipherOutputStream cipherOutputStream = new CipherOutputStream(objectOutputStream, cipherEncrypt);
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(sendingClientFile));
int count = 0;
while ((count = bufferedInputStream.read(buffer, 0, buffer.length)) != -1) {
//objectOutputStream.write(buffer, 0, count);
cipherOutputStream.write(buffer, 0, count);
}
bufferedInputStream.close();
//objectOutputStream.flush();
cipherOutputStream.flush();
}
Server code. Receiving a file.
ServerSocketFactory serverSocketFactory = SSLServerSocketFactory.getDefault();
serverSocket = serverSocketFactory.createServerSocket(port);
Socket clientSocket = serverSocket.accept();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(clientSocket.getOutputStream());
ObjectInputStream objectInputStream = new ObjectInputStream(clientSocket.getInputStream());
[...]
byte[] buffer = new byte[1024];
int i = 0;
int receivingClientFiles = (int) objectInputStream.readObject();
while(i < receivingClientFiles) {
[...]
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(diretorio + "/" + fileName));
int count = 0;
int received = 0;
while (received < fileLength) {
count = objectInputStream.read(buffer, 0, buffer.length);
bufferedOutputStream.write(buffer, 0, count);
received += count;
}
//while ((count = objectInputStream.read(buffer, 0, buffer.length)) != -1) {
// bufferedOutputStream.write(buffer, 0, count);
//}
bufferedOutputStream.close();
i++;
}
In count = objectInputStream.read(buffer, 0, buffer.length); you should max out on the file size (because you may otherwise read bytes from the next file). And that particular file size must be the encrypted length of the stream, not the original file size (if they differ, that is).

Not receiving any further messages after receiving a file over socket

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.

Send a video file from client to server and back

What I basically want is a simple video file transfer: when I press a button the client will send the file to the server and then the server sends the file back again to the client.
What I got now is just send from client to server and server receives it.
Here's some code to begin with :
Client :
System.out.println("Connecting...");
sock = new Socket(IP, PORT);
InputStream is = new FileInputStream(new File("FILE PATH"));
byte[] bytes = new byte[1024];
OutputStream stream = sock.getOutputStream();
int count = is.read(bytes, 0, 1024);
while (count != -1) {
stream.write(bytes, 0, 1024);
count = is.read(bytes, 0, 1024);
}
is.close();
stream.close();
sock.close();
System.out.println("2");
Server:
byte[] data = new byte[1024];
int count = fin.getInputStream().read(data, 0, 1024);
System.out.println("Receiving video...");
File video = new File("test.mp4");
FileOutputStream fos = new FileOutputStream(video);
while (count != -1) {
fos.write(data, 0, count);
count = fin.getInputStream().read(data, 0, 1024);
}
fos.close();
fin.close();
System.out.println("Done receiving");
Thanks.

Java Client and Server

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

File download from PC to Android device - OutputStream write( ) stucks for large files

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)).

Categories

Resources