Вопрос

In school we have a project where we have to send a file from server to a client. The problem we have is that when we transfer the file from the server to the client, the server shutsdown the connection. Here is our code so far:

Client:

    public static void main(String argv[]) throws Exception {

    int port = 8888;  //default
    if (argv.length
            > 0) {
        port = Integer.parseInt(argv[0]);
    }

    Socket clientSocket = new Socket("127.0.0.1", port);
    PrintStream outToServer = new PrintStream(
            clientSocket.getOutputStream());
    BufferedReader inFromServer = new BufferedReader(
            new InputStreamReader(clientSocket.getInputStream()));



    File f = new File("dictionaryPart.txt");

    String serverCommand = inFromServer.readLine().toLowerCase();
    while (serverCommand != null) {
        System.out.println(serverCommand);
        switch (serverCommand) {
            case "velkommen":
                outToServer.println("Hej");
                break;
            case "file":
                f = copy(clientSocket, f);
                String matches = CrackerCentralized.checkFile(f);
                System.out.println(matches);
                outToServer.println(matches);
                break;
        }
        serverCommand = inFromServer.readLine().toLowerCase();
    }
}

public static File copy(Socket clientSocket, File f) {
    try {
        int filesize = 2022386;
        int bytesRead;
        int currentTot = 0;

        byte[] buffer = new byte[filesize];
        InputStream is = clientSocket.getInputStream();
        FileOutputStream fos = new FileOutputStream(f);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        bytesRead = is.read(buffer, 0, buffer.length);
        currentTot = bytesRead;
        while (bytesRead != -1) {
            bytesRead = is.read(buffer, currentTot, (buffer.length - currentTot));
            if (bytesRead >= 0) {
                currentTot += bytesRead;
            }
        }
        bos.write(buffer, 0, currentTot);
        bos.flush();
        bos.close();
    } catch (IOException ex) {
        Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
    }
    return f;
}

Server:

    try {
        PrintStream outToClient = new PrintStream(connection.getOutputStream());
        OutputStream os = connection.getOutputStream();
        BufferedInputStream input = new BufferedInputStream(new FileInputStream(f));
        outToClient.println("file");
        final byte[] buffer = new byte[(int) f.length()];
        input.read(buffer, 0, buffer.length);
        os.write(buffer, 0, buffer.length);
        os.write(-1);
        os.flush();
        System.out.println(connection.isClosed());
        os.close();
        System.out.println(connection.isClosed());
    } catch (IOException ex) {
        Logger.getLogger(SocketController.class.getName()).log(Level.SEVERE, null, ex);
    }

I am aware of WHY the connection keeps on closing. We close the socket's output by writing

output.close();

But I don't know in what other way we must try to do this to make the server keep listening for the clients answer (match/no match), so that the server knows wether it should send more files or if the client was successful.. Is it even possible to send at file without shutting down the connection to the server? I've googled all day the last 2 days without any luck

Thanks for reading and for your help.

Это было полезно?

Решение

In order to implement what you are asking, you need to establish a communication protocol that the server and client understand. Something needs to be transmitted that says, "I'm starting to send information to you," and something that says, "I'm done sending stuff." There could be more -- such as information delimiting (e.g. Mime multipart form boundary). But at a minimum, you need the start and stop tokens.


Expanding on that: Look at the code in its simplest form: server:loop{write()} -> client:loop{read()}. Closing the stream on the server-side sends the -1 value to the client, which is usually consumed as the stop signal. If you want to maintain the connection indefinitely, and write to the client at different times, something has to be sent that says, "This transaction is complete". The following is pseudo-ish code -- freehand, not compiled.

// SERVER
private Socket socket; // initialized somewhere

private static final byte[] STOP = "</COMMS>".getBytes();

public void sendData(byte[] bytes) throws IOException{

  OutputStream out = socket.getOutputStream();

  if(bytes != null){
      out.write(bytes,0,bytes.length);
  }

  out.write(STOP);
}  // notice we exit the method without closing the stream.

// CLIENT
private Socket socket; // initialized somewhere
private static final byte[] STOP = "</COMMS>".getBytes();
private static final int BUFFER_SIZE = 1024 << 8;
private InputStream in;

public byte[] receiveData(){
    if(in == null){
      in = socket.getInputStream();
    }
    byte[] content;
    byte[] bytes = new byte[BUFFER_SIZE];
    int bytesRead;
    while((bytesRead = in.read(bytes)) != -1){  // normal termination
          if(receivedStop(bytes,bytesRead)){  // see if stopped
               removeStopBytes(bytes,bytesRead); // get rid of the STOP bytes
               content = buildContent(content,bytes,bytesRead); // transfer bytes to array
               break;
          }
          content = buildContent(content,bytes,bytesRead); // transfer bytes to array
    }
    return content;
}

Again, that was freehand and not compiled or tested. I'm sure it's not fully correct but hopefully you get the gist. The server writes content but never closes the stream. The client reads the stream looking for the STOP content, building up the final content until the stop is reached.

Другие советы

Thanks to madConan for the reply, it gave me a good idea of how to do it. I will post my code here, so others can use it in future.

SERVER CODE

    public void run() {
    try {
        PrintStream outToClient = new PrintStream(connection.getOutputStream());
        OutputStream os = connection.getOutputStream();
        BufferedInputStream input = new BufferedInputStream(new FileInputStream(f));
        outToClient.println("file");
        copy(input, os, f);
        System.out.println(connection.isClosed());
    } catch (IOException ex) {
        Logger.getLogger(SocketController.class.getName()).log(Level.SEVERE, null, ex);
    }
}

private static void copy(final InputStream is, final OutputStream os, File f) throws         IOException {
    final byte[] stop = "stop".getBytes();
    final byte[] buffer = new byte[(int) f.length()];
    is.read(buffer, 0, buffer.length);
    os.write(buffer, 0, buffer.length);
    os.write(stop);
    os.flush();
}

CLIENT CODE

    public static File recieveData(Socket clientSocket, File f) {
    try {
        InputStream in = clientSocket.getInputStream();
        FileOutputStream output = new FileOutputStream(f);
        byte[] content;
        byte[] bytes = new byte[1024 << 8];
        int bytesRead;
        while (true) {
            if (recieveStop(f)) {
                removeStop(f);
                break;
            }
            bytesRead = in.read(bytes);
            output.write(bytes, 0, bytesRead);
        }
    } catch (IOException ex) {
        Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
    }
    return f;
}

public static boolean recieveStop(File f) {
    BufferedReader br = null;
    try {
        br = new BufferedReader(new FileReader(f));
        String currentLine;
        String lastLine = "";
            while ((currentLine = br.readLine()) != null) {
                lastLine = currentLine;
            } 
        if (lastLine.equals("stop")) {
            return true;
        }
    } catch (FileNotFoundException ex) {
        Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
            Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
        try {
            br.close();
        } catch (IOException ex) {
            Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    return false;
}

public static void removeStop(File f) {
    try {
        RandomAccessFile raFile = new RandomAccessFile(f, "rw");
        long length = raFile.length();
        raFile.setLength(length - 4);
        raFile.close();
    } catch (FileNotFoundException ex) {
        Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
        Logger.getLogger(Master_Slave_Sockets_Client.class.getName()).log(Level.SEVERE, null, ex);
    }

}

Hope this will help others with the same problem.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top