Как да спрете програма, изпълняваща безкраен цикъл при затваряне на GUI (java)

Имам проста програма за комуникация сървър/клиент с помощта на сокети. Сървърният клас съдържа run() метод, този метод има безкраен цикъл за изчакване за приемане на сокет.

Както и да е, написах код в конструктора, за да направя прекратяване за обработка при затваряне,

 this.addWindowListener(new java.awt.event.WindowAdapter() {
    @Override
    public void windowClosing(java.awt.event.WindowEvent windowEvent) {
        System.out.println("Close operation server done");
        toClient.println("Bye");
        closeStreams();
        socket = null;
        serverSocket = null;
        System.exit(0);
    }
});

Когато прочетох API за метод windowClosing(WindowEvent e) казва:

Извиква се, когато прозорец е в процес на затваряне. Операцията за затваряне може да бъде отменена в този момент.

Пишекога прозорецът е в процес на затваряне. Но цикълът в метода run() все още получава контрола и няма да завърши поради логиката на програмата, така че прозорецът няма да бъде затворен (всъщност GUI е затворен), но обработката все още работи зад кулисите.

Актуализация:

методът run():

public void run()
{
    try
    {
        while (true)
        {
            idle = true;
            System.out.println("System is running");
            socket = serverSocket.accept();
            System.out.println("Client accepted on server side");
            openStreams();
            toClient.println("Hello: server is connected " + serverAddress.getLocalHost().toString());
            processClient();
            //   closeStreams();
        }
    } catch (Exception e)
    {
        System.out.println("Error accepting server " + e);
    }
}

processClient() метод:

 public void processClient() throws IOException
    {
        System.out.println("Porcessing start");
        String line = fromClient.readLine();
        try
        {
            while (!(line.equals("Bye")))
            {
                textToReceive.append("He: " + line + newline);
                line = fromClient.readLine();
            }
            closeStreams();

        } catch (IOException ex)
        {
            System.out.println("Error reading from client " + ex);
        }
    }

Как правилно да наложа програмата да не работи?

Актуализация 2: Целият работещ сървърен клас:

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.*;
import java.net.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;

/**
 *
 * @author S
 */
public class ChatServer extends JFrame
{

    private InetAddress serverAddress;
    private Socket socket;
    private ServerSocket serverSocket;
    private InputStream is;
    private OutputStream os;
    private BufferedReader fromClient;
    private PrintWriter toClient;
    private JButton send;
    private JPanel uperPanel;
    private JPanel midPanel;
    private JPanel downPanel;
    private JTextArea textToSend;
    private JTextArea textToReceive;
    private JLabel addressL;
    private final int port = 5555;
    private boolean idle = false;
    private int timeout = 3000;
    public static String newline = System.getProperty("line.separator");

    private ChatServer()
    {
        this.setGUI();
        this.setVisible(true);
        try
        {
            serverSocket = new ServerSocket(port);
            this.run();
        } catch (IOException ex)
        {
            Logger.getLogger(ChatServer.class.getName()).log(Level.SEVERE, null, ex);
        }

        this.addWindowListener(new java.awt.event.WindowAdapter()
        {
            @Override
            public void windowClosing(java.awt.event.WindowEvent windowEvent)
            {
                idle = true;
                closeStreams();
                socket = null;
                serverSocket = null;
                System.exit(0);
            }
        });
    }

    public void run() throws IOException
    {
        try
        {
            while (true)
            {
                System.out.println("System is running");
                socket = serverSocket.accept();
                System.out.println("Client accepted on server side");
                openStreams();
                toClient.println("Hello: server is connected " + serverAddress.getLocalHost().toString());
                processClient();
                //   closeStreams();
            }
        } catch (java.net.SocketTimeoutException ee)
        {

            closeStreams();
            System.out.println(ee);


        } catch (Exception e)
        {
            System.out.println("Error accepting server " + e);
        }

    }

    public void processClient() throws IOException
    {
        System.out.println("Porcessing start");
        String line = fromClient.readLine();
        try
        {
            while (!(line.equals("Bye")))
            {
                textToReceive.append("He: " + line + newline);
                line = fromClient.readLine();
            }
            closeStreams();

        } catch (IOException ex)
        {

            System.out.println("Error reading from client " + ex);

        }
    }

    private void setGUI()
    {

        this.setSize(375, 314);


        send = new JButton("send");

        try
        {
            addressL = new JLabel("My Server address: " + serverAddress.getLocalHost().toString()
                    + "  Port: " + this.port);
        } catch (Exception e)
        {
            System.out.println("Unknown Host problem " + e);
        }

        textToReceive = new JTextArea(12, 30);
        textToReceive.setLineWrap(true);
        JScrollPane recievedScrolledText = new JScrollPane(textToReceive);
        recievedScrolledText.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        textToReceive.setEditable(false);


        textToSend = new JTextArea(3, 25);
        textToSend.setLineWrap(true);
        JScrollPane sentScrolledText = new JScrollPane(textToSend);
        sentScrolledText.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        textToSend.setEditable(true);

        uperPanel = new JPanel();
        midPanel = new JPanel();
        downPanel = new JPanel();

        uperPanel.add(addressL);


        midPanel.add(recievedScrolledText);
        downPanel.add(sentScrolledText);
        downPanel.add(send);

        Container c = getContentPane();
        c.setLayout(new BorderLayout());
        c.add(uperPanel, "North");
        c.add(midPanel, "Center");
        c.add(downPanel, "South");

        send.addActionListener(new ButtonWatch());
        textToSend.addKeyListener(new KeyWatch());
    }

    private void openStreams() throws IOException
    {

        is = socket.getInputStream();
        fromClient = new BufferedReader(new InputStreamReader(is));
        os = socket.getOutputStream();
        toClient = new PrintWriter(os, true);
        System.out.println("open stream is open on server");
    }

    private void closeStreams()
    {
        try
        {

            if ((toClient != null) && (os != null)
                    && (fromClient != null) && (is != null)
                    && (fromClient != null) && (socket != null))
            {
                toClient.close();
                os.close();
                fromClient.close();
                is.close();
                socket.close();
            }


        } catch (IOException ex)
        {
            System.out.println("Problem closing streams " + ex);
        }
    }

    private class KeyWatch extends KeyAdapter
    {

        public void keyPressed(KeyEvent e)
        {
            if (e.getKeyCode() == KeyEvent.VK_ENTER)
            {
                String line = textToSend.getText();
                textToSend.setText("");
                toClient.println(line);
                textToReceive.append("You: " + line + newline);
            }
        }

        public void keyReleased(KeyEvent e)
        {
            if (e.getKeyCode() == KeyEvent.VK_ENTER)
            {
            }
        }

        public void keyTyped(KeyEvent e)
        {
            if (e.getKeyCode() == KeyEvent.VK_ENTER)
            {
            }
        }
    }

    private class ButtonWatch implements ActionListener
    {

        @Override
        public void actionPerformed(ActionEvent e)
        {
            Object buttonPressed = e.getSource();

            if (buttonPressed == send)
            {
                String line = textToSend.getText();
                textToSend.setText("");
                toClient.println(line);
                textToReceive.append("You: " + line + newline);

                System.out.println("send to client " + line);
            }

        }
    }

    public static void main(String[] args)
    {
        ChatServer s = new ChatServer();
        s.setVisible(true);
    }
}

Сега как да го прекратите след затваряне.


person Saleh Feek    schedule 30.11.2012    source източник
comment
Демонстрирайте своя цикъл. Като цяло, правилният начин би бил да се задържи препратка към нишката, която изпълнява цикъла и да извика Thread.interrupt, където методът run проверява редовно състоянието Thread.interrupted().   -  person Marko Topolnik    schedule 30.11.2012
comment
безкрайният цикъл е причинен в кодови редове, които не сте показали, обзалагам се, че кодовият ред е 57-ми. или/и с 875th., за по-добра помощ по-рано публикувайте SSCCE, демонстриращ вашия проблем за сутринта, кратък, работещ, компилируем, за затваряне на Socket и празен JFrame, в противен случай всичко тук е изстрел в тъмното,   -  person mKorbel    schedule 30.11.2012
comment
срещу каквото и да е от отговорите тук, повечето (затваряне чрез използване на методи, внедрени в API) работни нишки и връзка, Socker, RMI, cobra .... са асинхронни, тогава няма гаранция, че зависи от, скрийте JFrame и след това направете somenting с terminate/ затваряне/изтичане/каквото и да е, но няма проблем със Socket по подразбиране, грешката на OPs не е публикувана, нито описана   -  person mKorbel    schedule 30.11.2012
comment
Актуализирам въпроса си, ако знаете как да го накарате да прекрати, просто кажете. Благодаря   -  person Saleh Feek    schedule 30.11.2012
comment
възможен дубликат на Как да спрете програма, изпълняваща безкраен цикъл при затваряне GUI   -  person Boann    schedule 24.01.2015


Отговори (2)


- Добре е да използвате Executor за обхващане на нишката.

- След това използвайте метода cancel(true) с submit(), за да прекъснете тази конкретна нишка.

- Ако искате да отидете директно с Thread, тогава можете да използвате метода interrupt() или interrupted(), за да прекъснете thread.

person Kumar Vivek Mitra    schedule 30.11.2012

Променете цикъла на сървъра си така, че да не бъде безкраен.

volatile boolean runFlag = true;
while (runFlag) {
  //do server stuff
}

и вземете вашия метод за затваряне, за да маркирате сървъра да спре.

this.addWindowListener(new java.awt.event.WindowAdapter() {
  @Override
  public void windowClosing(java.awt.event.WindowEvent windowEvent) {
    System.out.println("Close operation server done");
    toClient.println("Bye");
    closeStreams();
    runFlag = false;
  }
});

Може да искате да преместите нещата за затваряне на потока след цикъла на главния сървър, така че всички неща, които са в ход, да бъдат завършени и да не прекъсвате нищо, което се извършва в момента.

person Qwerky    schedule 30.11.2012