3

Hello there im trying to send files using client-server classes in java. For some reason when the method that sends the file is called the socket closes. here is the code :

FileInputStream fIn = new FileInputStream(file);
out = new BufferedOutputStream(clientSocket.getOutputStream());
byte fileContent[] = new byte[(int) file.length()];
fIn.read(fileContent);
for (byte b : fileContent) {
    out.write(b);
}

and the code from the client :

FileOutputStream fIn = new FileOutputStream("testing");
BufferedInputStream inAout = new BufferedInputStream(clientSocket.getInputStream());
byte fileContent[] = new byte[1000000];
inAout.read(fileContent);
fIn.write(fileContent);

and the error message i get : SEVERE: null java.net.SocketException: Socket closed

Im not really experienced with this so if any can help it would be great.

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
Giannis
  • 5,286
  • 15
  • 58
  • 113
  • I know there are some things that need to be fixed like naming and the size on fileContent of client so please comment on the code ^^. – Giannis May 23 '11 at 15:50
  • can you show how you're opening the sockets -- i believe that's where the problem might be! – Liv May 23 '11 at 15:57
  • welcomeSocket = new ServerSocket(4351); Socket clientSocket = welcomeSocket.accept(); This problem occurs only when sending a file . When sending text messages it works fine. – Giannis May 23 '11 at 16:08

3 Answers3

14

The InputStream.read(byte[]) method returns an int for the number of bytes it actually read. It's not guaranteed to read as many bytes as you requested from the byte array. It'll often return the size of the underlying buffer and you'll have to call it many times.

You can use this to be more efficient by streaming the bytes from the socket to the file instead of buffering the whole byte array in memory. Likewise on the server side you can do the same thing to save memory and be faster than writing a byte at a time.

Here's a working example of a server and client in one that connects to itself to transfer a file:

public class SocketFileExample {
    static void server() throws IOException {
        ServerSocket ss = new ServerSocket(3434);
        Socket socket = ss.accept();
        InputStream in = new FileInputStream("send.jpg");
        OutputStream out = socket.getOutputStream();
        copy(in, out);
        out.close();
        in.close();
    }

    static void client() throws IOException {
        Socket socket = new Socket("localhost", 3434);
        InputStream in = socket.getInputStream();
        OutputStream out = new FileOutputStream("recv.jpg");
        copy(in, out);
        out.close();
        in.close();
    }

    static void copy(InputStream in, OutputStream out) throws IOException {
        byte[] buf = new byte[8192];
        int len = 0;
        while ((len = in.read(buf)) != -1) {
            out.write(buf, 0, len);
        }
    }

    public static void main(String[] args) throws IOException {
        new Thread() {
            public void run() {
                try {
                    server();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();

        client();
    }
}
WhiteFang34
  • 70,765
  • 18
  • 106
  • 111
  • wow that looks convenient . Ill try to get it to add this to my code now . Thanks – Giannis May 23 '11 at 16:15
  • No problem. Oops, I just realized my answer was backwards for your question. I updated it to have the server send the file (originally I had the client sending the file). Either way the logic is basically the same though. – WhiteFang34 May 23 '11 at 16:21
  • In order for the copying to be completed the streams must be closed. But then the program cant continue working because the connection is lost.Is there any way to get around this ? – Giannis May 23 '11 at 17:35
  • You don't have to close the socket streams. You won't however know when the end of the file is with this example though. You could send the file size prior to sending the file bytes to accomplish this. You'd want to wrap the server `OutputStream` with a `DataOutputStream` and call `writeInt(fileSize)`. Likewise on the client side wrap the `InputStream` with a `DataInputStream` and call `readInt()` to know how many bytes to process. It'll make the copying logic a little more complicated to handle the end of the file as well. – WhiteFang34 May 23 '11 at 17:41
0

The reason is pretty simple: The call inAout.read(fileContent) will return after about 4KB of data has been transmitted. That's the input buffer size. So instead of a single huge read, you need a loop and many reads and write as many bytes to fIn as you got from the socket.

Also don't forget to flush the output on the server side (closing will flush it) or some data will be lost.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • Although i cant find any method that will check if there is anything more coming like .ready or something like that . SO what condition would that loop have ? – Giannis May 23 '11 at 16:07
  • You probably want to send the expected size of eth file, somehow. Then you want to consume bytes (and write them to disk) until the requisite number of bytes have been read off the wire. If you want to be sufficiently paranoid, you then ship a hash of the file, compute a hash of eth received file and compare these. – Vatine May 23 '11 at 16:31
  • Haven't done this in a long time. You have two options: 1. Send the file size as a String (with a new line) before the data. 2. Loop until read() returns 0 or throws an EOFException. Not sure which one happens in this case, just give it a try. – Aaron Digulla May 24 '11 at 08:19
0
SEVERE: null java.net.SocketException: Socket closed

That means you've closed the socket yourself and then called another operation that needs it open. For example, closing the socket or its input stream or output stream closes the other stream and the socket. Somewhere or other you are doing that.

user207421
  • 305,947
  • 44
  • 307
  • 483