代码之家  ›  专栏  ›  技术社区  ›  loloof64

为什么这个客户端/服务器程序不停止?

  •  0
  • loloof64  · 技术社区  · 13 年前

    在学习java套接字的过程中,我在两个框架中进行了一次功能性但非常简单的聊天:一个客户端和一个服务器。该应用程序仅在本地运行。但当我关闭窗口时,它并没有停止(尽管我在两个框架类中都添加了WindowListener):怎么了?

    不要忘记先运行服务器,然后再运行客户端:只有在客户端连接之后,这两个帧才可见。

    这是SimpleSocketFrame.java(两个框架的基类):

    package com.loloof64.java_se.simple_socket;
    
    import java.awt.GridLayout;
    import java.awt.event.KeyAdapter;
    import java.awt.event.KeyEvent;
    
    import javax.swing.JFrame;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    
    public abstract class SimpleSocketFrame extends JFrame {
    
        public SimpleSocketFrame() {
            setTitle(getFrameTitle());
            setLayout(new GridLayout(0, 1));
    
             messageToAddField = new JTextField(30);
         messageToAddField.addKeyListener(new KeyAdapter() {
    
                @Override
                public void keyReleased(KeyEvent e) {
                    if (e.getKeyCode() == KeyEvent.VK_ENTER){
                        if ( ! messageToAddField.getText().isEmpty()) {
                            addMessage(messageToAddField.getText());
                            messageToAddField.setText("");
                        }
                    }
                }
    
        });
    
            printedMessagesArea = new JTextArea(10,30);
            printedMessagesArea.setEditable(false);
    
            add(messageToAddField);
            add(printedMessagesArea);
    
        pack();
    }
    
    protected abstract void addMessage(String s);
    protected abstract String getFrameTitle();
    
    private static final long serialVersionUID = -5861605385948623162L;
    protected JTextArea printedMessagesArea;
    private JTextField messageToAddField;
    
    }
    

    这是服务器应用程序类:SimpleSocketServer.java

    package com.loloof64.java_se.simple_socket;
    
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    import javax.swing.JOptionPane;
    
    public class SimpleSocketServer extends SimpleSocketFrame {
    
        public SimpleSocketServer(){
            super();
            setTitle("Simple Server");
            try {
                serverSocket = new ServerSocket(12345);
                relatedSocket = serverSocket.accept();
    
                outStream = new PrintStream(relatedSocket.getOutputStream());
                isr = new InputStreamReader(relatedSocket.getInputStream());
                inStream = new BufferedReader(isr);
    
                final InStreamRunnable inStreamRunnable = new InStreamRunnable();
                Thread inStreamReaderThread = new Thread(inStreamRunnable);
    
    
    
                addWindowListener(new WindowAdapter() {
    
                    @Override
                    public void windowClosing(WindowEvent evt) {
                        try {
                            inStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        try {
                        isr.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                        outStream.close();
                    try {
                        relatedSocket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    try {
                        serverSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                        inStreamRunnable.stop();
                        System.exit(0);
                    }
    
                });
    
                inStreamReaderThread.start();
            } catch (IOException e) {
                JOptionPane.showMessageDialog(this, "Could not create the server !!!",
                        "Fatal error", JOptionPane.ERROR_MESSAGE);
                System.exit(1);
                e.printStackTrace();
            }
        }
    
        private class InStreamRunnable implements Runnable {
    
            @Override
            public void run() {
                while (weMustGoOn){
                    String line;
                    try {
                        line = inStream.readLine();
                                       printedMessagesArea.setText(printedMessagesArea.getText()+line+"\n");
                    } catch (IOException e) {
    
                    }
                }
        }
    
            public void stop(){
                weMustGoOn = false;
            }
    
            private boolean weMustGoOn = true;
    
        }
    
        @Override
        protected void addMessage(String s) {
            s = "Serveur> "+s;
            outStream.println(s);
            printedMessagesArea.setText(printedMessagesArea.getText()+"Client> "+s+"\n");
        }
    
        @Override
        protected String getFrameTitle() {
            return "Simple Server";
        }
    
        public static void main(String[] args) {
            new SimpleSocketServer().setVisible(true);
        }
    
        private static final long serialVersionUID = 4288994465786972478L;
        private Socket relatedSocket;
        private ServerSocket serverSocket;
        private PrintStream outStream;
        private InputStreamReader isr;
        private BufferedReader inStream;
     }
    

    这是客户端类:SimpleSocketClient.java

    package com.loloof64.java_se.simple_socket;
    
    import java.awt.event.WindowAdapter; 
    import java.awt.event.WindowEvent;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.InetAddress;
    import java.net.Socket;
    
    import javax.swing.JOptionPane;
    
    public class SimpleSocketClient extends SimpleSocketFrame {
    
        public SimpleSocketClient(){
            try {
                socket = new Socket(InetAddress.getLocalHost(), 12345);
                outStream = new PrintStream(socket.getOutputStream());
    
            isr = new InputStreamReader(socket.getInputStream());
                inStream = new BufferedReader(isr); 
    
                final InStreamRunnable inStreamRunnable = new InStreamRunnable();
            Thread inStreamReaderThread = new Thread(inStreamRunnable);
    
                addWindowListener(new WindowAdapter() {
    
                    @Override
                    public void windowClosing(WindowEvent evt) {
                    try {
                            inStream.close();
                    } catch (IOException e2) {
                        e2.printStackTrace();
                    }
                    try {
                        isr.close();
                    } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                    outStream.close();
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    inStreamRunnable.stop();
                    System.exit(0);
                }
    
            });
                inStreamReaderThread.start();
        } catch (IOException e) {
                JOptionPane.showMessageDialog(this, "Could not create the client !!!",
                        "Fatal error", JOptionPane.ERROR_MESSAGE);
                System.exit(1);
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            new SimpleSocketClient().setVisible(true);
        }
    
    private class InStreamRunnable implements Runnable {
    
        @Override
        public void run() {
                while (weMustGoOn){
                String line;
                try {
                    line = inStream.readLine();
                          printedMessagesArea.setText(printedMessagesArea.getText()+line+"\n");
                    } catch (IOException e) {
    
                    }
                }
            }
    
        public void stop(){
            weMustGoOn = false;
        }
    
        private boolean weMustGoOn = true;
    
        } 
    
    @Override
    protected void addMessage(String s) {
        s = "Client> "+s;
        outStream.println(s);
        printedMessagesArea.setText(printedMessagesArea.getText()+s+"\n");
    }
    
    @Override
        protected String getFrameTitle() {
        return "Simple Client";
    }
    
        private static final long serialVersionUID = 5468568598525947366L;
        private Socket socket;
        private PrintStream outStream;
        private InputStreamReader isr;
        private BufferedReader inStream;
    
    
     } 
    
    2 回复  |  直到 13 年前
        1
  •  2
  •   Reimeus    13 年前

    当你试图关闭网络输入时,程序不会停止 Readers 关闭时 JFrame ,它们正在无限期地阻塞。 BufferedReader InputStreamReader 对象无法关闭,因为客户端线程在此被阻止 readLine 正在等待服务器响应的调用

    line = inStream.readLine();
    

    注释掉或删除:

    inStream.close();
    

    isr.close();
    

    只是关闭 Socket 流就足够了。

    除此之外: 当与多线程网络应用程序的Swing组件交互时,请始终使用 SwingWorker . SwingWorkers 设计用于与Swing组件正确交互。

        2
  •  2
  •   boomz    13 年前

    您应该添加 finally 在之后阻止 try catch 关闭套接字,然后可以通过系统退出方法关闭程序。