Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/384.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 检查插座端接是否异常_Java_Sockets - Fatal编程技术网

Java 检查插座端接是否异常

Java 检查插座端接是否异常,java,sockets,Java,Sockets,我正在编写一个带有会话线程的服务器,用于与客户端的开放连接。这相当简单,它只是使用一个缓冲读取器从输入中读取行。如果该行等于一个表示用户想要退出的特殊值,或者为空,则循环终止。否则,消息将沿着链传递给要处理它的模块。出于测试的目的,我只是简单地远程登录到我的服务器并手动输入命令 如果可以,除非我通过键入QUIT以外的方式终止连接,例如关闭终端窗口。然后生成一条具有未知字符序列的消息,并将一条格式错误的消息传递到链上。在这个简单的测试用例中,这并不重要,但它确实指出了一个需要解决的问题 我的代码如

我正在编写一个带有会话线程的服务器,用于与客户端的开放连接。这相当简单,它只是使用一个缓冲读取器从输入中读取行。如果该行等于一个表示用户想要退出的特殊值,或者为空,则循环终止。否则,消息将沿着链传递给要处理它的模块。出于测试的目的,我只是简单地远程登录到我的服务器并手动输入命令

如果可以,除非我通过键入QUIT以外的方式终止连接,例如关闭终端窗口。然后生成一条具有未知字符序列的消息,并将一条格式错误的消息传递到链上。在这个简单的测试用例中,这并不重要,但它确实指出了一个需要解决的问题

我的代码如下

    public void run () {
        BufferedReader  inReader;
        UpstreamMessage message;
        String          lastLine;

        Thread.currentThread ().setName ("UpstreamThread_" + outer.getId ());

        try {
            inReader    = new BufferedReader (new InputStreamReader (outer.clientSocket.getInputStream (), "UTF8"));
            while (!this.ending) {
                // Read whatever was in the input buffer
                lastLine    = inReader.readLine ();
                Logger.getLogger (this.getClass ().getName ()).log (Level.INFO, "Last data from input stream reader was \"{0}\"", lastLine);
                if (null != lastLine && !lastLine.equals ("QUIT")) {
                    message = new UpstreamMessage (outer.sessionId, lastLine);
                    outer.server.acceptMessage (message);
                } else {
                    // End the session
                    Logger.getLogger (this.getClass ().getName ()).log (Level.INFO, "Thread ending");
                    break;
                }
            }
        } catch (IOException | IllegalArgumentException ex) {
            Logger.getLogger (this.getClass ().getName ()).log (Level.SEVERE, ex.getMessage (), ex);
        } catch (InterruptedException ex) {
            // This is thrown when we're telling the thread to shut down so it's normal
            Logger.getLogger (this.getClass ().getName ()).log (Level.INFO, ex.getMessage (), ex);
        } finally {
            this.terminate ();
        }
    }
当我关闭终端窗口时,我的控制台输出以下日志:

2013年7月27日下午7:37:00 bikeshop.server.Session$UpstreamChannel运行 信息:来自输入流读取器的最后数据为 “”

有时,记录器会报告以下情况,表明lastMessage变量引用了null,但null检查失败

2013年7月27日下午7:37:00 bikeshop.server.Session$UpstreamChannel运行 信息:来自输入流读取器的最后一个数据为“null”

我显然做错了什么,但我不知道是什么。当我退出终端时,我的测试“if(null!=lastLine&!lastLine.equals(“QUIT”))没有捕获缓冲区中的任何结果。我怎样才能更优雅地处理这个案子

编辑:对日志和单步调试进行更仔细的分析后发现,当您退出telnet客户端时,它会发送一系列控制字符。这将从缓冲区读取并向上传递链,从而在程序的其他部分触发警告。然后会话再次执行循环,并尝试从现在已关闭的套接字读取。这将返回null,循环终止。这就是从客户机读取的最后一行是否为空的混淆源。最后一次读取的内容确实为空,但倒数第二次读取才是最重要的一次读取,它触发了异常行为

所以我猜问题已经变成了a)退出telnet客户端时发送什么控制序列,或者b)Java知道如何检查该控制序列吗

BufferedReader.readLine()
如果按照文档关闭套接字,则返回
null
。if语句的第一个条件如下所示:

if (null != lastLine && !lastLine.equals ("QUIT"))
如果是这种情况(或者,您的计算机已损坏;),则计算结果将为
false

如果您的日志显示为“null”,并且它的计算结果不是
false
。。。然后字符串包含实际文本“null”。将其放入调试器中,在此循环中设置断点,然后逐步查看
lastLine
的值;你会看到发生了什么

也就是说,编写服务器的第一条规则是永远不要信任客户机。就像在使用telnet的情况下,最终你无法控制发送给你的内容


当您从该套接字读取数据时,您需要进行更多的输入验证,这样您就不会试图处理无效的内容。您的方法会有所不同,但通常的解决方案是有效命令的映射、验证输入结构的正则表达式等。不这样做会导致服务器软件非常脆弱,您已经发现了这一点

readLine()
如果按照文档关闭套接字,则返回
null
。您的
if
语句的第一个条件(或者,您的计算机坏了;)如图所示。如果您的日志显示为“null”,而不是。。。然后字符串包含实际文本“null”。把它放在调试器中,一步一步地进行,你会看到发生了什么。我已经完成了,变量watch告诉你,当你退出终端时,你会在最后一个读取行中得到一个字符串。它们似乎是不可打印的字符,因此我在日志记录和调试器中会显示一个空格字符串。显然,一个不可打印字符的字符串不是空的,并且错误的分支被采用。第二个注意:telnet不是一个“原始”套接字协议。它做的额外的东西可能不是你想要的。使用真正的测试客户端,而不是telnet。我正在使用telnet客户端进行调试。似乎当您退出时,它会发送一系列控制字符。这些字符不是null或QUIT,因此它们被发送到链的上游,服务器再次循环。当它通过该循环时,从缓冲区读取的数据返回null,循环结束。这就是为什么我在日志中得到一个空值,但测试失败的原因。我理解这一点。重要的是,你无法对发送给你的信息采取任何措施。我对输入验证部分进行了编辑以进行扩展-在发送输入之前,您需要查找与预期不符的内容。@GordonM Brian就在这里。如果您无法处理Telnet在终止时发送的额外内容,请不要使用Telnet作为客户端,或者在服务器上实现Telnet协议,以便您能够理解它。