В случае с PrintWriter, почему я должен сбрасывать в цикле, а не после цикла?

У меня есть Сервер и Клиент в моей маленькой демонстрационной программе, где я отправляю какие-то строковые данные с Клиента на Сервер, а после этого повторно отправляю эти данные для Клиента, который также выписывает их в консоль. Меня смутил метод сброса PrtintWriter, который, согласно документации JAVA, очищает поток. После некоторых исследований я знакомлюсь с концепцией autoflash: когда параметр autoFlash имеет значение true, методы println, printf или format будут очищать выходной буфер. Единственное, чего я здесь не понимаю, так это почему я должен использовать метод сброса PrintWriter в цикле, а не после цикла. (В моем случае я использую PrintWriter на стороне сервера.) Autoflash делает то же самое, потому что метод println() тоже находится в цикле. Когда я использую флеш после цикла, мои строковые данные не отображаются на консоли. Спасибо за ваши рекомендации и помощь заранее!

Клиент:

public class ClientDemo {
public static void main(String[] args) throws IOException {

    final String CLIENTNAME = "<CLIENT>:";
    final String SERVERADDRESS = "localhost";
    final int PORT = 12312;

    try {
        Socket socket = new Socket(SERVERADDRESS, PORT);
        PrintWriter out =
          new PrintWriter(socket.getOutputStream(), true);                   
        Scanner scanner = new Scanner(socket.getInputStream());

        System.out.println(CLIENTNAME + "Client starts");
        List<String> lista = getList();

        for(String userInput : lista){
            out.println(userInput);
            System.out.println("echo: " + scanner.nextLine());
        }

    } catch(IOException e) {
        System.out.println(CLIENTNAME + "Error connecting to the server:" + e.getMessage());
    }
}

  private static List<String> getList(){
        List<String> result = new ArrayList<>();
        result.add("egy");
        result.add("ketto");
        result.add("harom");
        result.add("negy");

        result.add("ot");
        result.add("hat");
        result.add("het");
        result.add("nyolc");
        result.add("kilenc");
        result.add("tiz");

        return result;
    }
}

Сервер:

public class ServerDemo {
public static void main(String args[]) throws IOException {

    final int PORT = 12312;
    final String SERVERNAME ="<SERVER>:";

    try {
        ServerSocket serverSocket = new ServerSocket(PORT);
        Socket socket = serverSocket.accept();
        PrintWriter printWriter = new PrintWriter(socket.getOutputStream());
        Scanner scanner = new Scanner(socket.getInputStream());

        System.out.println(SERVERNAME + "Server starts...");

        String inputLine;
        while(scanner.hasNext()) {
            inputLine = scanner.nextLine();
            printWriter.println(inputLine);
            printWriter.flush();
        }

    } catch (IOException e) {
        System.out.println(SERVERNAME + "Error handleing client...");
    } 
   }
}

person F3R1    schedule 13.04.2016    source источник


Ответы (1)


Вам не нужно вызывать flush после написания каждой строки. Вы блокируете ввод-вывод, делая это. Вызывая flush, вы гарантируете, что каждая строка, которую вы записываете в сокет, действительно записывается, а не просто буферизуется (будет записана позже). Буферизация повышает производительность ввода-вывода. Но здесь кажется, что по каким-то причинам вы не используете преимущества, которые дает буферизация. Вы блокируете до тех пор, пока запись не будет полностью завершена.

person VHS    schedule 13.04.2016
comment
Прежде всего, спасибо за ваш ответ. Во-вторых, не могли бы вы дать мне более подробное объяснение того, как я могу заблокировать ввод-вывод, выполнив сброс в цикле? Потому что, если я удалю строку сброса, список строк не появится в консоли. Мой учитель также предупредил меня, чтобы я использовал метод смыва. и как видите, в моем примере я не использую ни автофальш, ни close. Заранее спасибо еще раз! - person F3R1; 14.04.2016
comment
Вы должны попытаться закрыть объект PrintWriter в блоке finally сразу после блока catch. Прямо сейчас вы не закрываете ресурс PrintWriter. Если вы закроете ресурс, он также очистит его перед закрытием. В этот момент все строки в буфере будут сброшены (записаны) в место назначения. Попробуйте добавить блок finally и закрыть ресурс PrintWriter. Вы должны увидеть вывод на консоли. Вы также можете использовать новый оператор try-with-resources Java 7, чтобы вам не приходилось закрывать какие-либо ресурсы, которые реализуют интерфейс AutoClosable. - person VHS; 14.04.2016
comment
Если я закрою ресурс в блоке finally и удалю сброс из кода или перенесу его после цикла, к сожалению, он также выдаст ту же ошибку, и я не увижу вывод на консоли. Я знаю оператор try-with-resource, я переписываю код с его помощью, и возникает тот же симптом. Если флеш находится в цикле, вывод находится на консоли... если он удален из цикла или после цикла, я не вижу вывод. (Кстати, я ценю вашу помощь. Я уже проголосовал за вас. После того, как я заработаю волшебные 15 высокой репутации, вы это увидите.:)) - person F3R1; 14.04.2016