Java File Transfer getting stuck halfway - java

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.

Related

Socket hangs when trying to read input stream from web browser Java

I am attempting to read an input stream from a socket provided by a web browser client. Every approach I have taken has got the same results thus far, it just hangs and I don't know why. I have tried mark() marking the read limit to what is available and still no go.
inputStream.mark(inputStream.available());
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024 * 9];
int read;
while((read = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, read);
}
byte[] bytes = outputStream.toByteArray();
I have also tried clientSocket.shutdownInput() to tried to fix this issue, still no good.
Here is my attempt below:
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Server {
public static void main(String[] args)
{
ServerSocket server = null;
try {
// Server is listening on port 3001
server = new ServerSocket(3001, 1, InetAddress.getByName("localhost"));
server.setReuseAddress(true);
// running infinite loop for getting
// client request
while (true) {
// socket object to receive incoming client
// requests
Socket client = server.accept();
// Displaying that new client is connected
// to Server
System.out.println("New client connected"
+ client.getInetAddress()
.getHostAddress());
// create a new thread object
ClientHandler clientSock
= new ClientHandler(client);
// This thread will handle the client
// separately
new Thread(clientSock).start();
}
}catch (IOException e) {
e.printStackTrace();
}
}
// ClientHandler class
private static class ClientHandler implements Runnable {
private final Socket clientSocket;
// Constructor
public ClientHandler(Socket clientSocket)
{
this.clientSocket = clientSocket;
}
public void run() {
InputStream inputStream = null;
OutputStream clientOutput = null;
try {
inputStream = clientSocket.getInputStream();
inputStream.mark(inputStream.available());
clientSocket.shutdownInput();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024 * 9];
int numRead;
while((numRead = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, numRead);
}
byte[] bytes = outputStream.toByteArray();
String payloadString = new String(bytes, StandardCharsets.UTF_8);
System.out.println(payloadString);
clientOutput = clientSocket.getOutputStream();
clientOutput.write(("HTTP/1.1 \r\n" + "200 OK").getBytes());
clientOutput.write(("ContentType: " + "text/html" + "\r\n").getBytes());
clientOutput.write("\r\n".getBytes());
clientOutput.write("Hello World!".getBytes());
clientOutput.write("\r\n\r\n".getBytes());
clientOutput.flush();
inputStream.close();
clientOutput.close();
try{
clientSocket.close();
}catch(Exception ex){
ex.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Any help would be most appreciated! Thank you.
browsers suggests you should toss this all in the garbage and use HTTP, because, well, browsers.
But, if you insist, there are two problems here.
You've made it crazy complicated.
You can take all of that code and replace it all with this simple little line:
byte[] bytes = in.readAllBytes();
That replaces the lines starting with in.mark(in.available()) (this line does nothing at all, I have no idea where you got this from. If you think it is supposed to do something specific, you might want to mention that. Because it doesn't do anything. mark is useful if you ever reset, which you aren't, and you don't need to here, hence, useless), all the way to `byte[] bytes =...;
sockets don't close unless sender goes out of its way to close it
Your read code (yours, or the much simpler one-liner above) reads everything until the stream closes. In your second snippet, you close it right away, which obviously doesn't work. You cannot know when to close it, the sender does this job. Evidently it's not doing it.
I advise you to adapt protocols that pre-roll sizes, so you know how much to read and aren't dependent on closing the socket just to signal that the data is sent.
For example:
byte[] sizeRaw = in.readNBytes(4);
int size = ByteBuffer.wrap(bytes).getInt();
byte[] bytes = in.readNBytes(size);
You will of course have to adjust the sending code to send the size first (as a 32-bit value, big endian). One way or another you have to look at the sending code here. Either fix it so that it closes once done, or, better yet, adjust it so it sends size first.

multiple input of different data type from a single client to server (JAVA)

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.

Why doesn't DataInputStream continue to receive data after reading binary file

I'm creating a server to receive both text and binary data from clients. It works with text data as well as the first time receiving binary file, but after this it didn't continue to reading data and throw an exception.
Here is my server code:
public class ConnectedProcessThread implements Runnable{
private final Socket socket;
public ConnectedProcessThread(Socket clientSocket){
socket = clientSocket;
}
public void run(){
DataInputStream dis = null;
try{
while(true) {
dis = new DataInputStream(socket.getInputStream());
String meta = dis.readUTF();
Log.i("Data received", meta);
if(meta.equalsIgnoreCase("Text")){
String message = dis.readUTF();
Log.i("Data received", message);
}else if(meta.equalsIgnoreCase("Binary")){
InputStream is = socket.getInputStream();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
int len;
while((len=is.read(buf))>-1){
stream.write(buf,0,len);
}
stream.flush();
//read object input
try {
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(stream.toByteArray()));
byte[] buffer = (byte[])ois.readObject();
FileOutputStream fos = new FileOutputStream("/storage/emulated/0/DCIM/IMG-Saved.jpeg");
fos.write(buffer);
}catch (ClassNotFoundException e){
e.printStackTrace();
}
finally {
Log.i("Binary_Transfer","File created");
}
}
}
} catch (IOException e){
e.printStackTrace();
}finally {
Log.i("Client_Socket","Stream will close");
if(dis!=null){
try {
dis.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
For both text and binary data, before sending the data, client will sent text meta-data to inform the server the data is text or binary. But after receiving a file(image), it throws an EOFException at line: String meta = dis.readUTF(); I guessed it happened because after reading and writing binary file, the thread continues to loop so DataInputStream will read again, and now there's nothing to receive so readUTF() throws EOFException. I tried to send a meta-data from client after sending the binary file to let DataInputStream can read something and not throw an exception, but it didn't work, the client did send the meta-data but the server still throws EOFException. Anyone knows what the problem is? Thanks so much.
Here is my send binary method from client:
public void sendBinaryData(byte[] binaryData){
if(dos!=null && socket!=null){
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(binaryData);
Log.d("Binary_Transfer", "C: Sent.");
oos.close();
dos.writeUTF("Binary_End");
dos.flush();
}catch (Exception e){
Log.e("File_Exception",e.toString());
}
}
}
Because when you start reading the binary data, you enter a loop that only terminates at end of stream, i.e. when the peer disconnects:
while((len=is.read(buf))>-1){
stream.write(buf,0,len);
}
At that point you are at the end of the stream. There was no more data, there is no more data, and there never will be any more data.
You need to completely remove this part:
InputStream is = socket.getInputStream();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
int len;
while((len=is.read(buf))>-1){
stream.write(buf,0,len);
}
stream.flush();
There is rarely any point in reading things into ByteArrayOutputStreams anyway, and this is no exception. Just remove that completely, and change the next part:
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(stream.toByteArray()));
to
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
and continue as you are already. However you have another problem:
oos.close();
This closes the socket. So the next part:
dos.writeUTF("Binary_End");
dos.flush();
cannot possibly work. Just flush the ObjectOutputStream instead of closing it.
But I would strongly suggest you discard the DataInput/OutputStreams and use a single ObjectInput/OutputStream for the life of the socket, at both ends.

Proper way of closing Streams in Java Sockets

I saw some posts about this but I still can't find an answer.
This is how my server interacts with the client:
public void run () {
try {
//Read client request
InputStream is = server.getInputStream();
byte[] buff = new byte[1024];
int i;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((i = is.read(buff, 0, buff.length)) != -1) {
bos.write(buff, 0, i);
System.out.println(i + " bytes readed ("+bos.size()+")");
}
is.close();
is = null;
//Do something with client request
//write response
OutputStream os = server.getOutputStream();
os.write("server response".getBytes());
os.flush();
os.close();
os = null;
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
And this is the client side:
public void run() {
try {
InetAddress serverAddr = null;
serverAddr = InetAddress.getByName("10.0.2.2");
socket = new Socket(serverAddr, 5000);
//Send Request to the server
OutputStream os = socket.getOutputStream();
os.write(jsonRequest.toString().getBytes("UTF-8"));
os.flush();
os.close();
os = null;
//Read Server Response
InputStream is = socket.getInputStream();
byte[] buff = new byte[1024];
int i;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((i = is.read(buff, 0, buff.length)) != -1) {
bos.write(buff, 0, i);
System.out.println(i + " bytes readed ("+bos.size()+")");
}
is.close();
is = null;
//Do something with server response
} catch (UnknownHostException uhe) {
sendCallbackError(uhe);
} catch (IOException ioe) {
sendCallbackError(ioe);
}
}
As you can see, the client connects and send a request. Server read that request then writes a response that the client will read.
The problem with this code is the OutputStream.close() in the client and InputStream.close() in the server. As stated in the Javadocs, closing the stream will close the Socket. The result is that when the client tries to read the server response, the Socket is already closed.
I've managed to overcome this by calling Socket.shutdownInput and Socket.shutdownOutput instead. However I am still thinking whether this is the proper way of doing it
As a note, closing the streams with close() when server writes the response or when the client reads it doesn't create problems (I would guess the closing is synchronized between client and server).
So my questions are:
Is using the Socket shutdown methods a proper way?
Can I keep closing the last streams with close() (when sending and reading
response from server)
Could it happen that closing with shutdown would keep some data in
the buffer and wouldn't be sent?
You can do the following:
try{
}catch(){
}finally{
if(is!=null){
is.close();
}
if(os!=null){
os.close();
}
}
The problem with this code is the OutputStream.close() in the client and InputStream.close() in the server. As stated in the Javadocs, closing the stream will close the Socket.
Correct but the InputStream in the server isn't connected directly to a Socket: it is connected to something you don't know anything about. You can close it with impunity, although again you don't need to close it at all. You can close the OutputStream in the server if you like: although, again, as it isn't connected directly to a Socket, it may or may not have any effect other than flushing.
To address your actual question, you don't need to close the output stream in the client, but you do need to send an appropriate Content-Length: header. That way the server knows how much to read from the client. If this is only a GET request the content-length may well be zero. You don't need to call shutdownOutput(), although I guess there is nothing to stop you, and calling shutdownInput() doesn't do anything to the network anyway so again there is no point to it.

Keep Socket alive while send file

Iam sending a image from my android to pc ,its part of my app, Iam using sockets for this The sending part code includes
public void sendfile()
{
try {
System.out.println("looppppppp");
File file = new File(Environment.getExternalStorageDirectory()+ File.separator + "test.jpg");
byte [] mybytearray = new byte [(int)file.length()];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
System.out.println("Send:"+mybytearray.length);
bis.close();
OutputStream ous = socket.getOutputStream();
System.out.println("Sending...");
ous.write(mybytearray,0,mybytearray.length);
ous.flush();
//ous.close();
// socket.close();
System.out.println("send overrrrrrrrrrr");
}catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The Socket is connected in a thread when the program starts.
The receiver is a java code in pc as follows
#Override
public void run()
{
try
{
ServerSocket servsocket = new ServerSocket(13267);
System.out.println("Thread Waiting...");
Socket socket = servsocket.accept();
System.out.println("Accepted connection : " + socket);
System.out.println("Connected..");
while(true)
{
// filesize temporary hardcoded
long start = System.currentTimeMillis();
int bytesRead;
int current = 0;
mybytearray = new byte [filesize];
File f=new File("d:\\ab.jpg");
f.createNewFile();
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream(f);
BufferedOutputStream bos = new BufferedOutputStream(fos);
System.out.println("b4");
bytesRead = is.read(mybytearray,0,mybytearray.length);
System.out.println("after");
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();
long end = System.currentTimeMillis();
System.out.println(end-start);
bos.close();
fos.close();
}
}catch(IOException e)
{
System.out.println("errorr");
}
}
}
The problem is File Does'nt appear on my pc Unless i close my output stream or socket If i close output stream the socket is getting closed why this?
Keep Socket alive while send file
Sending the file keeps the socket alive. I don't see the relevance of your title to your question.
The problem is File Does'nt appear on my pc Unless i close my output stream or socket
So close it. Closing the socket at the sender causes the receiver to exit your receive loop, which has no other way of exiting. Your stream copy loops are far more elaborate than necessary. It is neither necessary nor advisable to buffer entire files in memory before or after sending.
If i close output stream the socket is getting closed why this?
Because that's what it's specified to do. Closing the input or output stream of a socket closes the other stream and the socket.
If I understand correct you want to keep the socket open with the client, and also send files ...
My suggestion is :
- keep one main thread open to notify the server about new files
- open new threads to send each new file
- add code to control the maximum number of files that you can send at the same time (optional)
So the flow would be :
1. client open main socket
2. server open the main socket and assign a client id
3. client request the send of a new file
4. server keep in memory the file name and client id
5. server send response authorizing the client to send the file
6. client open a new thread to send the file

Categories