简体   繁体   中英

BufferedReader readLine() stuck

I'm writing a TCP multi Client/Server app that works in an infinite loop .

What happens:

  1. Client types "COMMANDS" and expects to get available commands from server.
  2. Server sends lines to client.
  3. Client reads server input line-by-line and is stuck after the last one is written .

Expected result:

  1. Client is prompted for keyboard input.
  2. Input is written to server.
  3. Server sends back text.
  4. Client reads server input line-by-line.
  5. End of loop. user types commands > server responds > user gets to type commands again

I know that BufferedReader would stop reading lines once I close the socket. However, that's not what we want since it has to work infinitely.

How do I exit the loop ?

Client method:

public class Client {
    private final Socket clientSocket;
    private final BufferedReader clientInput;
    private final PrintWriter clientOutput;
    private final BufferedReader keyboardInput;

    public Client() throws IOException {
        this.clientSocket = new Socket(InetAddress.getLocalHost(), 13370);
        this.clientInput = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        this.clientOutput = new PrintWriter(clientSocket.getOutputStream(), true);
        this.keyboardInput = new BufferedReader(new InputStreamReader(System.in));
    }

    public static void main(String[] args) throws IOException {
        Client client = new Client();
        client.init();
    }

    private void init() {
        try {
            while (true) {
                System.out.print("> ");
                String args = keyboardInput.readLine().trim().replaceAll("\\s+", " ");
                clientOutput.println(args.toUpperCase());

// the loops doesn't seem to stop after reading all input lines
                String line;
                while ((line = clientInput.readLine()) != null) {
                    System.out.println(line);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class ClientHandler implements Runnable {
    private final int id;
    private final Socket clientSocket;

    private final PrintWriter serverOutput;
    private final BufferedReader serverInput;

//  private final ClientFiles clientFiles;

    public int getId() {
        return id;
    }

    public ClientHandler(int id, Socket clientSocket) throws IOException {
        this.id = id;
        this.clientSocket = clientSocket;
        this.serverInput = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
        this.serverOutput = new PrintWriter(this.clientSocket.getOutputStream(), true);
//      this.clientFiles = new ClientFiles(id, clientSocket);
    }

    @Override
    public void run() {
        try {
            String command;
            while ((command = serverInput.readLine()) != null) {
                executeCommand(command.split(" "));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeConnection();
            removeFromHosts();
        }
    }

    private void executeCommand(String[] input) throws IOException {
        String command = input[0];
//      String option = input[1];

        switch (command) {
            case "COMMANDS": {
                getCommands();
                break;
            }
//          case "LIST_LOCAL": {
//              listFiles();
//              break;
//          }
//          case "LIST_FILES": {
//              listFiles(option);
//          }
//          case "PULL": {
//              pull(clientSocket, option);
//          }
//          case "PUSH": {
//              push(clientSocket, option);
//          }
            case "DISCONNECT": {
                closeConnection();
                break;
            }
            default: {
                write("Invalid command.");
                getCommands();
                break;
            }
        }
    }

    private String read() throws IOException {
        return serverInput.readLine();
    }

    private void write(String message) {
        serverOutput.println(message);
    }

    private void getCommands() {
        write("AVAILABLE COMMANDS:");
        write("\tCOMMANDS");
        write("\t\tlists available commands");
        write("\tLIST_HOSTS");
        write("\t\tlists hosts connected to server");
        write("\tLIST_FILES");
        write("\t\tlists files from all hosts connected server");
        write("\tLIST_LOCAL");
        write("\t\tlists local files");
        write("\tLIST_FILES [HOSTS]...");
        write("\t\tlists files from provided hosts connected server");
        write("\tPULL [HOST] [FILE]");
        write("\t\tdownloads file from host");
        write("\tPUSH [HOST] [FILE]");
        write("\t\tuploads file to host");
        write("\tDISCONNECT");
        write("\t\tdisconnects client from server");

    }

    private void closeConnection() {
        try {
            serverInput.close();
            serverOutput.close();
            clientSocket.close();
            removeFromHosts();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void removeFromHosts() {
        Server.getClients().remove(this);
    }
}

Server just accepts new clients and starts new threads.

public class Server {
    private static final AtomicInteger count = new AtomicInteger(1);
    private static final ArrayList<ClientHandler> clients = new ArrayList<>();

    public static void main(String[] args) {
        Server.init();
    }

    public static void init() {
        System.out.println("Opening server socket...");
        try (
            ServerSocket serverSocket = new ServerSocket(13370)
        ) {
            System.out.println("Server socket opened at port: " + serverSocket.getLocalPort());
            while (true) {
                System.out.println("Waiting for client connection...");
                Socket clientSocket = serverSocket.accept();
                System.out.println("Client connected.");
                ClientHandler client = new ClientHandler(count.getAndIncrement(), clientSocket);
                clients.add(client);
                System.out.println(clients);
                new Thread(client, "client-" + client.getId()).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static ArrayList<ClientHandler> getClients() {
        return clients;
    }
}

your client is waiting for more lines. In your code

   while ((line = clientInput.readLine()) != null) {
       System.out.println(line);
   }

clientInput.readLine() will never return null if server does not close the connection. The execution stops waiting more data.

I suggest to implements a solution like insert an empty line or a special char to signal the client that the response to the command is finished.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM