【问题标题】:Java app can't be closed even "CLOSE ON EXIT", TCP ServerJava应用程序即使“CLOSE ON EXIT”也无法关闭,TCP Server
【发布时间】:2016-05-07 18:47:58
【问题描述】:

我只想制作一个服务器应用程序,它可以获取字符串并将它们放入 JTextArea 中。我得到两个错误,甚至没有显示错误。

  1. 虽然我使用了这个语句,但窗口不能关闭:

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  2. 如果客户端连接到服务器,整个窗口变黑。可能是什么错误?代码如下:

客户:

public Main() {
    super("Main");
    setIconImage(Toolkit.getDefaultToolkit().getImage(Main.class.getResource("/images/ic.png")));

    panelFields = new JPanel();
    panelFields.setLayout(new BoxLayout(panelFields,BoxLayout.X_AXIS));
    panelFields2 = new JPanel();
    panelFields2.setLayout(new BoxLayout(panelFields2,BoxLayout.X_AXIS));

    scrollPane = new JScrollPane();
    panelFields.add(scrollPane);

    getContentPane().add(panelFields);
    getContentPane().add(panelFields2);
    getContentPane().setLayout(new BoxLayout(getContentPane(),BoxLayout.Y_AXIS));
    setSize(326, 264);
    setVisible(true);

    messagesArea = new JTextArea();
    scrollPane.setViewportView(messagesArea);
    messagesArea.setColumns(30);
    messagesArea.setRows(10);
    messagesArea.setEditable(false);

    startServer = new JButton("Start");
    startServer.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            socketConnection();
            startServer.setEnabled(false);
        }
    });

    panelFields.add(startServer);
}

和服务器连接:

private void socketConnection() {
    try {
        serverSocket = new ServerSocket(9090);
        System.out.println("Listening: " + serverSocket.getLocalPort());
    } catch (IOException e) {
        e.printStackTrace();
    }

    while (true) {
        try {
            socket = serverSocket.accept();
            dataInputStream = new DataInputStream(socket.getInputStream());
            System.out.println("ip: " + socket.getInetAddress());
            System.out.println("message: " + dataInputStream.readUTF());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (dataInputStream != null) {
                try {
                    dataInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

也许您可以告诉我,我该如何解决这些问题,以及如何让服务器不关闭套接字,尽管客户端断开连接。我想稍后重新连接...

【问题讨论】:

  • stackoverflow.com/questions/182316/… 的可能重复项。您的 socketConnection 方法永远不会结束,这意味着您的 ActionListener 永远不会返回,这会阻止 Swing 处理任何进一步的事件——包括表示标题栏关闭操作的 WindowEvents。始终在 AWT 事件调度线程以外的线程中执行冗长的操作。
  • 谢谢,我明白了。我只是在“新线程(){}”中完成了它,并且效果很好!你能告诉我,尽管第一个连接崩溃了,我怎么能一直在后台运行这个线程?

标签: java sockets tcp server


【解决方案1】:

您需要在自己的线程中启动套接字侦听器,并且您需要添加一个关闭该线程的窗口关闭侦听器。

例如:

private ServerSocket serverSocket = null;
private boolean done = false;

private void startServer() {
    Thread t = new Thread(new Runnable() {
        public void Run() {
            socketConnection();
        });
    }
    t.start();
}

private void socketConnection() {
    try {
        serverSocket = new ServerSocket(9090);
        System.out.println("Listening: " + serverSocket.getLocalPort());

        while (!done) {
            try {
                final Socket socket = serverSocket.accept();
                Thread t = new Thread(new Runnable() {
                    public void Run() {
                        handle(socket);
                    }
                });
                t.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private void handle(Socket socket) {
    if (socket == null) return;
    try {
        dataInputStream = new DataInputStream(socket.getInputStream());
        System.out.println("ip: " + socket.getInetAddress());
        System.out.println("message: " + dataInputStream.readUTF());
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (dataInputStream != null) {
            try {
                dataInputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        try {
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


public void windowClosing(WindowEvent e) { 
    done = true; 
    socketServer.close(); 
} 

您的按钮点击监听器应该调用 startServer(),然后您的窗口关闭函数将设置 done = true 并调用 socketServer.close()。

现在您有一个用于 UI 的线程,一个用于套接字服务器的线程,以及一个用于与服务器的每个连接的线程。

【讨论】:

  • 非常感谢您的快速答复!它帮助了我!我刚刚得到另一个问题......在连接发生之前,我无法将“完成”设置为真。所以首先,我将“完成”设置为假,然后......我什么时候将“完成”设置为真?我想让这台服务器保持活跃,以便我可以随时重新连接?
  • 只有在程序准备好关闭时才设置 done=true,所以在窗口关闭监听器中。
  • public void windowClosing(WindowEvent e) { done = true; socketServer.close(); }
  • 非常感谢!由于我可以关闭窗口并且整个应用程序停止工作,因此似乎我不需要窗口关闭侦听器。我是java新手,所以也许我错了。无论如何,非常感谢您的帮助!
  • 因为您设置了“退出时关闭”,它会在您关闭窗口时强制线程结束,因此您可以获得所需的效果。 :)
猜你喜欢
  • 1970-01-01
  • 2017-02-16
  • 1970-01-01
  • 2023-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-29
  • 2015-10-22
相关资源
最近更新 更多