0

情况

我一直在创建一个程序来在 LAN 中的两台计算机之间交换消息。一台计算机将自己标识为服务器,而另一台计算机则是客户端。启动时,用户必须输入另一台计算机的主机和端口,如果他希望作为客户端连接到该计算机。它如何工作的设置非常基本:你输入你的信息,按回车键,它就会显示在你自己的屏幕上。之后,您的对话伙伴必须单击一个按钮以检索最新消息,并且它应该显示在他的屏幕上。这种情况一直持续到有人离开。

问题

程序正确启动并要求连接设置。之后,我在两台计算机上都启动了连接,一切似乎都很好(建立连接后,标签会显示您的状态,例如客户端或服务器,是 (1))。当我输入一条消息并发送它时,事情继续看起来很好,输出被写入发件人的屏幕并且没有发生意外行为。

当我想在另一台计算机上检索消息时,程序完全冻结。GUI 中没有可点击的对象,也没有显示输出。

代码

假设连接正确建立(参见 (1)),我将在下面概述发送消息的过程,同时省略非必要部分。

GuiApplication.java

private void sendMessage() {
    connection.sendMessage(message);
    showMessage(message);
}

Connection.java
public void sendMessage(String message) {
    if (isClient()) {
        client.sendMessage(message);
    } else if (isServer()) {
        server.sendMessage(message);
    }
}

Client.java
public void sendMessage(String message) {
    outbound = new PrintWriter(socket.getOutputStream(), true); // Defined outside this method
    outbound.println(message);
}

发送消息的过程非常简单,但我想包含它以防我忽略了某些内容。

下面是我为检索新消息而创建的代码。这个概念很简单:我检查是否有任何新消息,如果有,我就检索它们。

GuiApplication.java
if (connection.hasNewMessage()) {
    message = connection.retrieveMessage();
}
showMessage(message);

第一部分 ( connection.hasNewMessage()) 将检查程序是否正在运行客户端或服务器并调用适当的retrieveMessage().

Client.java
public String retrieveMessage() throws IOException {
    inbound = socket.getInputStream(); // Defined outside this method
    return IOUtils.toString(inbound, "UTF-8");
}

起初我尝试BufferedReader使用一个InputStreamReader并调用该readLine()方法,但是一旦我发现它不起作用(与我目前面临的问题相同)就决定尝试 commons.io 方法。

问题

现在已经很清楚了:为什么我的程序会在我单击检索新消息的按钮时挂起?

外部的

我不确定它是否不受欢迎,但如果您想要更好的概述,这里是github 存储库,尽管我相信必要的代码剪辑器在那里。

4

2 回答 2

2

在不阅读您的所有解释和所有代码附件的情况下,我可以假设您正在读取或写入流到 UI 线程(例如,从 Action 或ActionListener直接调用 IO 操作并且您在读/写时被阻止。

请检查您的代码。我相信你会找到你打电话给in.read()或的地方out.write()。在该行之前和之后添加打印。你会看到你永远不会退出读或写。

这是因为对方没有进行相反的操作。所以,你必须:

  1. 将 UI 与 IO 分离。IO 必须在单独的线程中完成。
  2. 检查为什么其他方面会阻止您的流程。
于 2012-12-23T16:00:48.130 回答
2

我确实查看了您的代码,并且正如我所怀疑的那样,您的问题与您发布的代码完全无关。您的 GUI 完全忽略 Swing 线程规则,并在称为 Event D ispatch T 线程或 EDT 的主 Swing 事件线程调用长时间运行的任务。由于该线程负责所有 Swing 绘图和用户交互,因此您的 GUI 无法执行此操作并完全冻结。

有关这方面的详细信息,请阅读Swing中的并发。

下次,请发布一个sscce,这样我们就不必深入研究您的大量源代码!SSCCE 的关键是消除所有对您手头的问题不重要的代码。这不容易做到,需要你做很多工作来创建,以便它有足够的代码来运行,但不要太多以至于让我们淹没在代码中,但是你要求志愿者免费帮助你时间,所以要求不高。

祝你好运!

于 2012-12-23T16:15:41.083 回答