套接字连接的惯用异常处理

Idiomatic exception handling for socket connection

我正在尝试了解如何优雅地使用 scala.util.control.Exception 包。

更具体地说,我想将这段 Java 代码转换为功能方式:

public static boolean hostAvailabilityCheck() { 
    try (Socket s = new Socket(SERVER_ADDRESS, TCP_SERVER_PORT)) {
        return true;
    } catch (IOException ex) {
        /* ignore */
    }
    return false;
}

我可以在 Scala 中使用 try-catch-finally 做同样的事情,但我正在寻找更实用的方法。另请注意,此 Java 代码使用 try-with-resources,因此这意味着此代码无论如何都会关闭套接字(即使发生异常):socket.close()

---根据问题澄清进行编辑---

要在 scala 中以函数式风格使用自动资源管理,最简单的方法是使用 scala-arm 然后你可以写

import resource._

def hostAvailabilityCheck():Boolean= { 
  managed(new Socket(SERVER_ADDRESS, TCP_SERVER_PORT)).map(_=>true).opt.isDefined
}

如果您真的非常想使用 scala.util.control.Exception,您可以这样写:

import scala.util.control.Exception._
def hostAvailabilityCheck():Boolean= { 
  catching[IOException].opt(new Socket(SERVER_ADDRESS, TCP_SERVER_PORT)). isDefined
}
return false;

}

更好的是,您可以使用 Try 类型来执行此操作,在这种情况下,您的原始方法将变为:

def hostAvailabilityCheck():Boolean = { 
  Try(new Socket(SERVER_ADDRESS, TCP_SERVER_PORT)).isSuccess
}

从你的例子中不清楚你想用这个做什么,但它可能对 return Try 而不是布尔值有用,这样如果端口获取成功后,您不必等待 OS 级别的端口回收,然后再以更明确的方式重新绑定它。

def hostAvailabilityCheck(port: Int):Try[Socket] = { 
  Try(new Socket(SERVER_ADDRESS, port))
}

然后您的客户端代码可以尝试获取一个端口,直到它真正获得一个:

def acquire(port: Int):Socket={
  hostAvailabilityCheck(port).recoverWith(case t:Throwable => acquire(port)).get
}

这是一个幼稚的实现,因为它会触发一个无限循环等待端口可用,并且可能会尝试捕获不可恢复的错误,但它应该给您一般的想法。 该实现只有在您使用 0 作为端口值时才真正有用,在这种情况下,它会尝试各种随机端口,直到找到一个可用的端口。