1

I want to send multiple files with a socket connection. For one file it works perfectly, but if I try to send more than one (one at a time) I get a Socket Exception:

java.net.SocketException: socket closed

In general, my connection works like this:

  1. Server waits for connection
  2. Client connects to the server and sends a request for a certain file (string that contains the filename)
  3. Server reads the local file and sends it to the client
  4. Client sends another request for another file and continues at point 3.

The run-Method for the waiting-for-request-procedure looks like this:

@Override
public void run() {
    String message;
    try {
        while ((message = reader.readLine()) != null) {

            if (message.equals(REQUESTKEY)) {
                System.out.println("read files from directory and send back");
                sendStringToClient(createCodedDirContent(getFilesInDir(new File(DIR))), socket);
            } else if (message.startsWith(FILE_PREFIX)) {

                String filename = message.substring(FILE_PREFIX.length());
                try {
                    sendFile(new File(DIR + filename));
                } catch (IOException e) {
                    System.err.println("Error: Could not send File");
                    e.printStackTrace();
                }
            } else {
                System.out.println("Key unknown!");
            }
        }
    } catch (Exception ex) {

        ex.printStackTrace();
    }
}

and my sendFile() Method looks like this:

public void sendFile(File file) throws IOException {
    FileInputStream input = new FileInputStream(file);
    OutputStream socketOut = socket.getOutputStream();

    System.out.println(file.getAbsolutePath());
    int read = 0;
    while ((read = input.read()) != -1) {
        socketOut.write(read);
    }
    socketOut.flush();

    System.out.println("File successfully sent!");

    input.close();
    socketOut.close();
}

I think the problem lies in the socketOut.close(). Unfortunately, the method closes the socket connection too (problem for further connections). But if I leave out this closing the file-transfer doesn't work correctly: files arrive incomplete at the client.

How can I avoid or fix this problem? Or is there even a better way to transfer multiple requested files?

Thank you

Zain Aftab
  • 703
  • 7
  • 21
MS1
  • 508
  • 9
  • 23
  • 2
    You need to tell your client how big the files are. Otherwise you're just streaming bytes with no end. The client won't know when to stop reading. Think about the communication between the two (the protocol). – Sotirios Delimanolis Aug 01 '13 at 15:26

2 Answers2

1

I've rewritten your send file method slightly so that you can send multiple files, you will need to pass it the DataOutputStream and close the stream after you have sent all the files you wish to send.

When reading, you should use a DataInputStream and call long len = dis.getLong() and then read from the stream the len bytes, then repeat for the next file. You may find it useful to send the number of files at the start to.

public void sendFile(File file, DataOutputStream dos) throws IOException {
    if(dos!=null&&file.exists()&&file.isFile())
    {
        FileInputStream input = new FileInputStream(file);
        dos.writeLong(file.getLength());
        System.out.println(file.getAbsolutePath());
        int read = 0;
        while ((read = input.read()) != -1)
            dos.writeByte(read);
        dos.flush();
        input.close();
        System.out.println("File successfully sent!");
    }
}
Robadob
  • 5,319
  • 2
  • 23
  • 32
  • The question is about sending multiple files via a single socket connection. Hard to see how this qualifies as an answer. It is also extremely inefficient. – user207421 Jan 23 '16 at 03:03
  • @EJP If you check the code closely, it is only closing the `FileInputStream`, not the `DataOutputStream`, so I'm not sure how you expect to write a more efficient protocol (short of compressing the files on the fly). Also a `DataOutputStream` is constructed using the [`getOutputStream()`](https://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#getOutputStream()) method from a socket, It's just better practise (IMO) to pass around the stream, than to keep reconstructing it. So I'm not sure what part of their question this doesn't answer, especially given the quesiton authors response. – Robadob Jan 23 '16 at 16:50
0

You can define a simple protocol between client and server. Send the file length before file content. Use DataOutputStream / DataInputStream to send / read the length. Do not close the socket after each file.

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275