Java TCP服务器类抽象

时间:2016-03-20 10:49:43

标签: java serversocket ioexception abstraction

出于学习目的,我正在编写Java TCP服务器。这被包装到它自己的类SyteTCPServer中,它使用ServerSocket来处理连接逻辑。这适用于学校项目,其中良好的代码实践非常重要。

它被放入自己的类的原因是因为有一个特定的应用程序级协议。该课程是大型项目的一部分。

当谷歌搜索时,我只发现人们将所有ServerSocket及其附带的逻辑直接放在主方法中。我不确定在OOP方面该怎么做?

我的SyteTCPServer有一个简单的Start()Stop()方法,它隐藏了使用ServerSocket,处理客户端等的实现。

但是,我有点难过,因为有很多网络功能,IntelliJ警告我要捕获IOExceptions。接受客户端可能会抛出IOException,因此可以获取所述客户端的输出流,因此可以writeBytes,...您明白我的观点。

在抽象的背景下,我如何才能最好地解决这些异常?我是否在方法旁边写了throws IOException,将较高代码try...catch设为SyteTCPServer.Start

此外,如果整个服务器停止必须发生任何异常,或者我“隐藏”其中一个客户端未正确连接的事实?或者,当客户端连接失败时,我应该触发事件吗?我真的不知道..

由于UI /核心代码分离,我还避免在因瘟疫而发生异常时编写输出。

我希望这些问题不会太多。

这是我的start方法的示例,抛出IOException:

public void Start() throws IOException {
    this.listenSocket = new ServerSocket(this.port);

    Listen();
}

2 个答案:

答案 0 :(得分:1)

我认为区分您可能收到的不同IOExceptions非常重要。例如,在连接已经建立的情况下创建新连接是一个例外,它是否是一个预期的错误?最简单的方法是阅读documentation并根据具体情况处理错误:

用于构建服务器套接字:

  

public ServerSocket(int port)抛出IOException

     
      
  • IOException - 如果在打开套接字时发生I / O错误。
  •   
  • SecurityException - 如果存在安全管理器且其checkListen方法不允许该操作。
  •   
  • IllegalArgumentException - 如果port参数超出指定的有效端口值范围,介于0和65535之间(包括0和65535)。
  •   

接受连接:

  

public Socket accept()抛出IOException

     
      
  • IOException - 如果在等待连接时发生I / O错误。
  •   
  • SecurityException - 如果存在安全管理器且其checkAccept方法不允许该操作。
  •   
  • SocketTimeoutException - 如果之前使用setSoTimeout设置了超时并且已达到超时。
  •   
  • IllegalBlockingModeException - 如果此套接字具有关联的通道,则该通道处于非阻塞模式,并且没有可以接受的连接
  •   

等等。

关于在何处捕获异常:这还取决于您希望服务器在特定情况下执行的操作。但总的来说,捕捉“预期”错误并在那里处理它们,但将非故意错误提升到更高的水平。

我的意思是:

public void foo() throws IOException {
    try {
        serverSocket = new ServerSocket(PORT);
    } catch (IOException e) {
        // Port is in use -> perhaps retry on another port
        // If things fail, throw exception anyway
    } finally {
        if (!serverSocket.isClosed()) {
            try {
                serverSocket.close();
            } catch (IOException e) {
                // This exception is to be taken care of internally, not thrown
            }
        }
    }
}

另请注意,这不仅适用于服务器端,也适用于客户端。

写好你的服务器祝你好运!

答案 1 :(得分:1)

  

我只发现人们把所有的ServerSocket及其随附   直接在main方法内部的逻辑。我不确定是不是这样   谈到OOP?

将所有ServerSocket创建代码及其后续逻辑直接用main()方法接受,处理和读/写到客户端绝对不是一个好的OOP实践。

使用OOP,我们应该从对象的角度思考这些对象如何相互交互以满足所需的功能。每个对象都包含一个独特的责任。

  

接受客户端可能会抛出IOException,因此可以获取   所述客户端的输出流,所以可以写上字符,...你明白我的意思。

     

在抽象的背景下,我如何才能最好地实现这些目标   异常?我是否在方法旁边写了一个抛出IOException   更高级的代码尝试...抓住SyteTCPServer.Start?

我可以强调的几个最佳实践

  • 不要忘记使用所有必要信息记录异常,因为它是以后用于调试和其他改进的必不可少的工具。
  • 不要在流程中使用多个try / catch捕获相同的异常。
  • 除非真的不需要,否则不要在捕捉异常之后吞下异常并重新抛出异常。
  • 最后,如何处理异常还取决于它是否是可恢复的异常。如果不可恢复则记录异常,清理资源。如果可恢复,请记录异常并按照从异常中恢复的步骤进行操作。这里最好的指南是该API的javadoc。
  

此外,如果整个服务器停止必须发生任何异常,或者我   “隐藏”其中一个客户端连接不正确的事实?要么   也许,当客户端连接失败时,我应该触发事件吗?

当你开始实现代码时,我相信你会发现更多的类,其中一个可以在一个单独的线程中处理每个客户端连接请求,比如ClientConnectionHandler对象(Thread),这样其他客户端未被阻止。因此,每个客户端连接都将成为一个独立的执行线程。

使用此设计,如果异常特定于该客户端连接,则无需关闭整个服务器。只需终止该客户端线程并清理资源就足够了。