在下面的代码中,我试图建立一个聊天室,但它不起作用,因为当服务器 运行时,当我按下连接按钮(右端口和客户端)时,它什么都不做。如果我在actionPerformed()方法中取出线程,按钮会冻结并保持按下状态。
代码:
服务器:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.UIManager;
public class Server implements ActionListener, WindowListener {
private JButton clear;
private JButton sendToAll;
private JTextArea log;
private JTextField inpf;
private JFrame fr;
private ServerSocket ss;
private Socket sock;
private PrintWriter out;
private BufferedReader in;
private boolean accepted;
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
new Server().go();
} catch (Throwable e) {
ReportError(e);
}
}
private void go() throws Throwable {
accepted = false;
Starter s = new Starter();
int port = s.getPort();
ss = new ServerSocket(port);
fr = new JFrame("Consle Port: "+String.valueOf(port));
fr.setDefaultCloseOperation(0);
fr.addWindowListener(this);
clear = new JButton("Clear Consle");
sendToAll = new JButton("Send");
clear.addActionListener(this);
sendToAll.addActionListener(this);
inpf = new JTextField(20);
log = new JTextArea();
log.setEditable(false);
JScrollPane scr = new JScrollPane();
scr.setViewportView(log);
fr.setLayout(new GridLayout(2, 2));
fr.add(scr);
fr.add(clear);
JPanel pan = new JPanel();
pan.add(inpf);
JPanel p = new JPanel();
p.add(sendToAll);
fr.add(pan);
fr.add(p);
fr.setLocationRelativeTo(null);
fr.setSize(500, 500);
fr.setVisible(true);
log.append("Wating for one client...");
sock = ss.accept();
accepted = true;
log.append("A client has joined! Server now running!");
String str = "";
out = new PrintWriter(sock.getOutputStream());
in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
while((str = in.readLine()) != null) {
out.print(str+"\n");
out.flush();
log.append(str+"\n");
}
}
@Override public void actionPerformed(ActionEvent e) {
if(e.getSource() == clear) {
log.setText("");
}else if(e.getSource() == sendToAll) {
if(out != null) {
out.print("Server: "+inpf.getText()+"\n");
out.flush();
} else
JOptionPane.showMessageDialog(null, "Nobody has joined. You are not allowed to send messages.", "No sending messages.", JOptionPane.INFORMATION_MESSAGE);
inpf.setText("");
}
}
@Override public void windowOpened(WindowEvent e) {}
@Override public void windowClosing(WindowEvent e) {
try {
int i = 0;
if(accepted) {
i = JOptionPane.showConfirmDialog(null, "Are you sure you want to shut down the server?", "Shut Down", JOptionPane.YES_NO_OPTION);
if(i == 0) {
out.print("server.exit\n"); //Remember to encrypt "server.exit"
ss.close();
sock.close();
}
} else
i = JOptionPane.showConfirmDialog(null, "Nobody has joined. Are you sure you want to exit?", "Nobody Joined", JOptionPane.YES_NO_OPTION);
if(i == 0)
System.exit(0);
} catch (Throwable e1) {
ReportError(e1);
}
}
@Override public void windowClosed(WindowEvent e) {}
@Override public void windowIconified(WindowEvent e) {}
@Override public void windowDeiconified(WindowEvent e) {}
@Override public void windowActivated(WindowEvent e) {}
@Override public void windowDeactivated(WindowEvent e) {}
protected static void ReportError(Throwable error) {
if(error.getMessage() != null && error.getCause() != null)
JOptionPane.showMessageDialog(null, "This happend because "+error.getCause()+". A deatial message has been included: "+error.getMessage()+". Terminating...", error.getClass().getName(), JOptionPane.ERROR_MESSAGE);
else if(error.getMessage() != null && error.getCause() == null)
JOptionPane.showMessageDialog(null, "This happend because "+error.getCause()+". No deatial message was included. Terminating...", error.getClass().getName(), JOptionPane.ERROR_MESSAGE);
else if(error.getMessage() == null && error.getCause() != null)
JOptionPane.showMessageDialog(null, "It is unknown why this error occured, but a deatial message has been included: "+error.getMessage()+". Terminating...", error.getClass().getName(), JOptionPane.ERROR_MESSAGE);
if(error.getMessage() == null && error.getCause() == null)
JOptionPane.showMessageDialog(null, "A "+error.getClass().getName()+" has occured. Terminating...", error.getClass().getName(), JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
private class Starter extends JFrame implements ActionListener {
private static final long serialVersionUID = -1841997198914785917L;
private JButton conf;
private JTextField pf;
public Starter() {
initGui();
desGui();
}
private void initGui() {
conf = new JButton("Host");
conf.addActionListener(this);
pf = new JTextField("Port", 7);
}
private void desGui() {
setLayout(new GridLayout(2, 1));
add(pf);
add(conf);
setTitle("Host a Server");
setDefaultCloseOperation(3);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
public int getPort() {
synchronized (this) {
try {
this.wait();
} catch (InterruptedException e) {
ReportError(e);
}
}
int i = 0;
try {
i = Integer.parseInt(pf.getText());
}catch(NumberFormatException e) {
JOptionPane.showMessageDialog(this, "The port entered was not valid. Terminating...", "Port Not Valid", JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
dispose();
return i;
}
@Override public void actionPerformed(ActionEvent e) {
synchronized (this) {
this.notifyAll();
}
}
}
}
客户端:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class Client implements WindowListener, KeyListener, ActionListener {
private JButton join;
private JButton clelog;
private JButton send;
private JTextField portf;
private JTextField clientf;
private JTextField mesf;
private JTextArea log;
private JFrame jfr;
private Socket sock;
private BufferedReader in;
private PrintWriter out;
private Client() throws Throwable {
jfr = new JFrame();
jfr.setLayout(new GridLayout(3, 1));
join = new JButton("Join");
join.addActionListener(this);
portf = new JTextField("Port", 7);
clientf = new JTextField("Client", 15);
jfr.add(portf);
jfr.add(clientf);
jfr.add(join);
jfr.pack();
jfr.setLocationRelativeTo(null);
jfr.setVisible(true);
}
@Override public void actionPerformed(ActionEvent e) {
if(e.getSource() == join)
SwingUtilities.invokeLater(new Runnable() {
public void run() {
join();
}
});
else if(e.getSource() == send)
send(mesf.getText());
else if(e.getSource() == clelog)
log.setText("");
}
private void join() {
jfr.dispose();
try {
Integer.parseInt(portf.getText());
}catch(NumberFormatException e2) {
JOptionPane.showMessageDialog(jfr, "The port entered was not valid. Terminating...", "Port Not Valid", JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
if(sock != null)
try {
sock.close();
} catch (IOException e1) {
reportError(e1);
}
try {
runProgram();
} catch (Throwable e1) {
reportError(e1);
}
}
private void runProgram() throws Throwable{
JFrame rfr = new JFrame("Consle");
rfr.setDefaultCloseOperation(0);
rfr.addWindowListener(this);
rfr.setLayout(new GridLayout(2, 2));
log = new JTextArea();
log.setEditable(false);
rfr.add(log);
mesf = new JTextField(20);
clelog = new JButton("Clear Consle");
send = new JButton("Send");
send.addActionListener(this);
clelog.addActionListener(this);
rfr.add(clelog);
JPanel pan = new JPanel();
JPanel p = new JPanel();
pan.add(mesf);
p.add(send);
rfr.add(pan);
rfr.add(p);
rfr.pack();
rfr.setLocationRelativeTo(null);
rfr.setVisible(true);
sock = new Socket(clientf.getText(), Integer.parseInt(portf.getText()));
out = new PrintWriter(sock.getOutputStream());
in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
String inp = "";
while((inp = in.readLine()) != null) {
log.append(inp+"\n");
}
}
@Override public void keyTyped(KeyEvent e) {}
@Override public void keyPressed(KeyEvent e) {}
@Override public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER) {
send(mesf.getText());
}
}
private void send(String text) {
out.print(mesf.getText()+"\n");
mesf.setText("");
}
@Override public void windowOpened(WindowEvent e) {}
@Override public void windowClosing(WindowEvent e) {
}
@Override public void windowClosed(WindowEvent e) {}
@Override public void windowIconified(WindowEvent e) {}
@Override public void windowDeiconified(WindowEvent e) {}
@Override public void windowActivated(WindowEvent e) {}
@Override public void windowDeactivated(WindowEvent e) {}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
new Client();
}catch(NumberFormatException e) {
JOptionPane.showMessageDialog(null, "The port you entered is not valid. Terminating...", "Port not valid", 0);
System.exit(0);
}catch(Throwable e) {
reportError(e);
}
}
protected static void reportError(Throwable error) {
if(error.getMessage() != null && error.getCause() != null)
JOptionPane.showMessageDialog(null, "This happend because "+error.getCause()+". A deatial message has been included: "+error.getMessage()+". Terminating...", error.getClass().getName(), JOptionPane.ERROR_MESSAGE);
else if(error.getMessage() != null && error.getCause() == null)
JOptionPane.showMessageDialog(null, "This happend because "+error.getCause()+". No deatial message was included. Terminating...", error.getClass().getName(), JOptionPane.ERROR_MESSAGE);
else if(error.getMessage() == null && error.getCause() != null)
JOptionPane.showMessageDialog(null, "It is unknown why this error occured, but a deatial message has been included: "+error.getMessage()+". Terminating...", error.getClass().getName(), JOptionPane.ERROR_MESSAGE);
else if(error.getMessage() == null && error.getCause() == null)
JOptionPane.showMessageDialog(null, "A "+error.getClass().getName()+" has occured. Terminating...", error.getClass().getName(), JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
}
答案 0 :(得分:1)
您正在事件调度线程上执行所有I / O操作,这会阻止所有UI更新。您需要生成一个单独的线程来侦听套接字上的传入消息,然后通过EventQueue
发送命令来更新UI。