问题
I have a simple program for server/client communication using sockets.
The server class contains run()
method, this method has infinite loop to wait for socket acceptance.
Any way, I wrote a code in the constructor to do termination for processing on close,
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);
}
});
When I read the API for the method windowClosing(WindowEvent e)
it says:
Invoked when a window is in the process of being closed. The close operation can be overridden at this point.
It says when a window is in the process of being closed. But the loop inside the run() method still gaining the control, and will not finish due to the logic of the program, so the window will not be closed (actually the GUI is closed) but the processing is still working behind the scenes.
How to correctly enforce the program from running?
The whole working server class:
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.*;
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);
}
}
Now how to terminate it correctly after clicking the (x) closing icon.
回答1:
Use a Thread
and set it as a daemon
thread. Here I changed the first few lines, of your code:
public class ChatServer extends JFrame implements Runnable
{
private ChatServer()
{
this.setGUI();
this.setVisible(true);
try
{
serverSocket = new ServerSocket(port);
Thread accept = new Thread(this);
accept.setDaemon(true);
accept.start();
} catch (IOException ex)
{
Logger.getLogger(ChatServer.class.getName()).log(Level.SEVERE, null, ex);
}
回答2:
ALSO:
Have you looked at setDefaultCloseOperation and a CloseListener window event handler?
回答3:
Close you server socket serverSocket.close()
in windowClosing
handler. This will throw SocketException
in your accept loop and interrupt it. You can catch it and process to make graceful shutdown.
来源:https://stackoverflow.com/questions/13651654/how-to-stop-program-running-infinite-loop-on-close-gui