在java中连接时客户端冻结

时间:2013-12-04 00:53:12

标签: java client-server

在下面的代码中,我试图建立一个聊天室,但它不起作用,因为当服务器 运行时,当我按下连接按钮(右端口和客户端)时,它什么都不做。如果我在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);
    }
}

1 个答案:

答案 0 :(得分:1)

您正在事件调度线程上执行所有I / O操作,这会阻止所有UI更新。您需要生成一个单独的线程来侦听套接字上的传入消息,然后通过EventQueue发送命令来更新UI。