2015-10-31 7 views
0

У меня есть простой сетевой код (я пытаюсь реализовать простой чат-сервер в качестве упражнения), но я застрял, и я не могу понять, что происходит. Я создаю GUI для своего клиента, и у него есть экземпляр другого класса, который выполняет все необходимые операции для подключения и отправки/получения сообщения на моем сервере.java бесконечный while loop нечетное поведение

package com.luca.chat; 

import java.awt.* 
import java.awt.event.* 
import javax.swing.* 

class Window extends JFrame { 

    private final static int WIDTH=500; 
    private final static int HEIGHT=300; 

    private String status="disconnected"; 

    private JPanel panel; 
    private JTextArea area; 
    private JTextField field,address; 
    private JButton button; 
    private JLabel label; 

    private IOClass io=new IOClass(this); 

    Window() { 
    super("Chit-Chat"); 
    setSize(new Dimension(WIDTH,HEIGHT)); 
    ImageIcon icon=new ImageIcon("..\\images\\lucas.png"); 
    setIconImage(icon.getImage()); 

    JPanel contentPane=(JPanel)getContentPane(); 

    // add the text area to display incoming and outgoing messages 
    area=new JTextArea(); 
    area.setEditable(false); 
    contentPane.add(area,BorderLayout.CENTER); 

    // add text field to send messages 
    field=new JTextField(20); 
    field.addActionListener(new ActionListener(){ 
     public void actionPerformed(ActionEvent e) { 
     String message=field.getText(); 
     io.send(message); 
     field.setText(""); 
     } 
    }); 
    panel=new JPanel(); 
    panel.add(field); 
    panel.setBorder(BorderFactory.createEtchedBorder()); 
    contentPane.add(panel,BorderLayout.SOUTH); 

    // add status bar on top 
    label=new JLabel("status: "+status); 
    address=new JTextField(15); 
    button=new JButton("connect"); 
    panel=new JPanel(); 
    panel.add(label); 
    panel.add(address); 
    panel.add(button); 
    button.addActionListener(new ActionListener(){ 
     public void actionPerformed(ActionEvent e) { 
     io.connect(address.getText()); 
     } 
    }); 
    panel.setBorder(BorderFactory.createEtchedBorder()); 
    contentPane.add(panel,BorderLayout.NORTH); 

    Toolkit kit=getToolkit(); 
    Dimension dim=kit.getScreenSize(); 
    setLocation((dim.width-WIDTH)/2,(dim.height-HEIGHT)/2); 
    setDefaultCloseOperation(EXIT_ON_CLOSE); 
    setVisible(true); 

    loop(); 
    } 

    void loop() { 
    while (true) 
     if (io.connected) 
     io.receive(); 
     else   // if I comment this line out it never calls receive() ?????  
     System.out.println("????"); 
    } 

    void setStatus(String status) { 
    label.setText(status); 
    } 

    void setText(String received) { 
    area.append(received); 
    } 

    public static void main(String[] args) { 
    new Window(); 
    } 


} 

IOClass имеет все методы для подключения/передачи/приема (я думаю, что он действует как-то контроллера? Я не знаю, я только начинаю изучать эти образцы) в флаг, который контролирует, установлено ли соединение или нет. Если есть соединение, он вызывает метод приема, который представляет собой бесконечный цикл для прослушивания входящих сообщений.

Но если я оставлю только оператор if (внутри цикла()) без else ... он не выполняется! Я имею в виду, что цикл while никогда не запускается (я пытался с некоторыми отпечатками ... никогда не добирался туда), но он добирается, если я добавляю другое!

, например, это блокирует на если заявление:

void loop() { 
    while (true) 
    if (io.connected) 
     io.receive(); 
} 

это работает (это время зацикливается):

void loop() { 
    while (true) 
    if (io.connected) 
     io.receive(); 
    else 
     ....do something else... 
} 

или даже это работает:

void loop() { 
    while (true) { 
    System.out.println("whatever"); 
    if (io.connected) 
     io.receive(); 
    } // end of while 
} 

I не может понять, это кажется мне очень странным поведением.

EDIT: с помощью функции отладки в Eclipse я вижу, что, когда он работает в то время цикла навсегда петли, как задумано, когда это не так просто БЛОКОВ на если условие

+0

Это неправда. Оператор if будет выполняться. Если бы я правильно понял ваш вопрос, вы могли бы вырезать почти весь код выше и все еще иметь всю необходимую информацию, чтобы задать этот вопрос. – user2651804

+0

@ user2651804 нет, это не будет. Даже когда метод подключения в IOClass устанавливает флаг в true – Luca

+0

Самое важное в таких вопросах, как это, является кратким примером, который компилирует и демонстрирует вашу проблему. Я предлагаю вам полностью paranthesize ваши 'while-loop' и' if-else'. Это может решить проблемы, которые у вас есть. – user2651804

ответ

0
void loop() { 
    while (true) 
     if (io.connected) 
     io.receive(); 
     else // if I comment this line out it never calls receive() ?????  
     System.out.println("????"); 
} 

В примере вашего ответ, вы указываете на этот код как на виновника. Поскольку while не имеет скобок {} Только следующая строка будет считаться телом цикла while. То же самое относится и к if без скобок: будет выполняться только первая строка в истинном состоянии. За ним может последовать или не следовать else.

В вашем случае, поскольку следующая строка после вашего while является if-else, и оба условия имеют только одну строку для выполнения, ваш цикл while работает так, как предполагалось.

Если то, что вы хотели сказать это:

void loop() { 
    while (true) 
     if (io.connected) 
     io.receive(); 
     //else 
     System.out.println("????"); 
} 

Тогда это не будет компилироваться, так как вы рассказываете System.out.println("????"); выполнить ПОСЛЕ цикл в то время как это делается, и состояние в то время как петли явно справедливо; Код никогда не будет достигнут. Если вместо этого вы используете переменную как флаг, она будет компилироваться, и вы увидите, что System.out.println("????"); будет выполняться один раз, когда цикл будет выполнен.

+0

нет, вы поняли это неправильно. Возможно, я был недостаточно ясен. Позвольте мне изменить мой вопрос – Luca

0

С помощью отладчика Eclipse, шаг за шагом, я смог найти уловку. С тех пор, как я создаю экземпляр JFrame, JVM автоматически закручивает новый поток (очередь событий), и поскольку он является ActionListener, зарегистрированным кнопкой подключения, вызывающей метод connect(), который устанавливает логический флаг в true, флаг true в этом одном потоке, но в основном потоке он все равно false, поэтому условие if никогда не оценивает значение true, поэтому я жду, когда метод receive() будет вызван, и я не получаю никакого вывода на экране. Использование изменчивого модификатора решает проблему, поэтому обновленная переменная автоматически отображается для всех потоков. Поскольку я новичок в потоках, это было не так очевидно ... но комментарий поставил меня в правильном направлении.