尝试从输入流中检索文本时,应用程序挂起

时间:2012-12-23 15:50:10

标签: java sockets io inputstream serversocket

情况

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

问题

程序正确启动并询问连接设置。之后,我在两台计算机上启动连接,事情似乎很顺利(建立连接后,标签会显示您的状态,例如客户端或服务器,是(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方法。工作(与我目前面临的问题相同)。

问题

现在已经非常清楚:为什么我的程序会在我点击一个检索新邮件的按钮时挂起?

外部

我不确定它是否令人不满,但是here's github存储库以防你需要更好的概述,尽管我相信必要的代码片段就在那里。

2 个答案:

答案 0 :(得分:2)

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

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

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

  1. 将UI与IO分离。 IO必须在单独的线程中完成。
  2. 检查为什么其他方会挡住您的流量。

答案 1 :(得分:2)

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

请阅读Concurrency in Swing了解详细信息。

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

祝你好运!