【问题标题】:Can't detect disconnect without extra readLine() loop没有额外的 readLine() 循环无法检测到断开连接
【发布时间】:2014-02-06 01:39:53
【问题描述】:

我正在开发一个使用套接字的程序,目前我的代码中有一个函数可以每秒检查来自客户端的心跳。

private void userLoop() { // checks for incoming data from client
    Timer t = new Timer();
    t.schedule(new TimerTask() {
        @Override
        public void run() {
            try {
                socketIn.read(); // check for heartbeat from client

                String userInput;
                while ((userInput = br.readLine()) != null) {
                }

            } catch (Exception e) {
                ControlPanel.model.removeElement(getUsername());
                ControlPanel.append(getUsername() + " has disconnected.");
            }
        }
    }, 1000);
}

当客户通过 X 按钮关闭游戏、关闭计算机、注销时,无论是什么原因,我都会收到“'用户名'已断开连接”的消息。这正是我想要的,但是,它只适用于代码中的 while 循环。 while 循环基本上什么都不做,我不知道为什么它不能用 out。

如果我删除 while 循环并使用客户端断开连接,则服务器端不会打印任何内容。

String userInput;
while ((userInput = br.readLine()) != null) {
}

上面基本上是死代码,没有它我的程序就不能按它应该的方式工作..

为什么需要该代码,我怎样才能删除它并仍然让我的程序正常工作?

【问题讨论】:

  • 什么是socketInbr 是什么?它们有关系吗?
  • br 在读什么?
  • The above is essentially the dead code。我不认为它死了。它一直读取缓冲的输入,直到它为空,这对我来说非常有意义。
  • 这里是 SSCE:pastebin.com/eUQrvgsu
  • @Ted Hopp,您的回答是正确的。 EJB 是错误的。客户端或服务器,当 InputStream 关​​闭并且您尝试从中读取时,它将抛出 IOException。

标签: java sockets loops timer while-loop


【解决方案1】:

在这种情况下,您的 while 循环实际上是在停止您的程序,直到您不再收到输入字符串。这不是死代码;这只是您安装等待的方式。

否则,根据我在Timer class 中的理解,它只等待一秒钟,这对于您等待捕获的内容可能太短了。

【讨论】:

  • 为什么太短了?我关闭了客户端的连接,我想要发生的是服务器从在线玩家列表中删除玩家。当有while循环时,这有效..
  • 你使用的方法是 schedule(TimerTask task, long delay_in_milliseconds)。听起来您通过将内容更改为 br.readLine(); 找到了答案,这意味着您需要阅读更多输入行(这就是 while 循环所做的事情)。
【解决方案2】:

我通过更改 try 块中的所有内容来解决我的问题

br.readLine();

【讨论】:

  • 就消耗流中的所有数据而言,这与循环具有相同的效果,但会花费更长的时间。计时器将为您执行循环。
  • 这就是我想要的 :p 只要它检测到玩家何时断开连接,一切都很好。
  • 这毫无意义。你不需要计时器。 readLine() 调用无论如何都会阻塞。如果对等方不发送数据,则代码无论如何只会执行一次。
【解决方案3】:

我听说过关于异常处理的说法:“异常应该只用于异常情况。”客户端与服务器断开连接也不例外。

既然我已经明白了,让我们继续吧。根据this other question, socket.getInputSteam.read() does not throw when I close the socket from the client 如果您在客户端正确关闭内容,听起来 read 调用不会抛出。

【讨论】:

    【解决方案4】:

    问题是当远程套接字关闭时,read() 并没有抛出异常,它只是返回-1 表示流结束。

    以下内容无需调用readLine()即可工作:

        try {
            int ret = socketIn.read(); // check for heartbeat from client
            if (ret == -1) {
                // Remote side closed gracefully
                clientDisconnected();
            }
        } catch (SocketTimeoutException e) {
            // Timeout -- handle as required
            handleTimeout();
        } catch (IOException e) {
            // Connection lost due to I/O error
            clientDisconnected()
        }
    

    【讨论】:

    • 你说对了一半。使用 read() 结果是正确的,但 IOException 可能是 SocketTimeoutException,这并不表示连接丢失。
    • 是的,我知道,但由于 OP 使用异常来检测“客户端断开连接”的情况,我假设他没有设置套接字超时超时。反正你是对的。我会编辑和澄清,谢谢你的评论!
    猜你喜欢
    • 2019-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-15
    • 1970-01-01
    • 1970-01-01
    • 2020-01-27
    相关资源
    最近更新 更多