Java:验证并将"host:port"转换为InetSocketAddress的常用方法?

jav*_*top 28 java sockets networking ports hostname

Java中用于验证表单字符串并将其转换host:port为实例的常用方法是InetSocketAddress什么?

如果满足以下条件,那将是很好的:

  • 没有地址查找;

  • 适用于IPv4,IPv6和"字符串"主机名;
    (对于IPv4来说ip:port,对于IPv6来说[ip]:port,对吧?是否有一些RFC定义了所有这些方案?)

  • 优选不用手解析字符串.
    (我正在考虑所有这些特殊情况,当有人认为他知道套接字地址的所有有效形式时,却会忘记导致意外结果的"特殊情况".)

jav*_*top 48

我自己提出了一种可行的解决方案.

将字符串转换为URI(这将自动验证它),然后查询URI的主机和端口组件.

遗憾的是,带有主机组件的URI必须有一个方案.这就是为什么这个解决方案"不完美"的原因.

String string = ... // some string which has to be validated

try {
  // WORKAROUND: add any scheme to make the resulting URI valid.
  URI uri = new URI("my://" + string); // may throw URISyntaxException
  String host = uri.getHost();
  int port = uri.getPort();

  if (uri.getHost() == null || uri.getPort() == -1) {
    throw new URISyntaxException(uri.toString(),
      "URI must have host and port parts");
  }

  // here, additional checks can be performed, such as
  // presence of path, query, fragment, ...


  // validation succeeded
  return new InetSocketAddress (host, port);

} catch (URISyntaxException ex) {
  // validation failed
}
Run Code Online (Sandbox Code Playgroud)

此解决方案不需要自定义字符串解析,可以使用IPv4(1.1.1.1:123),IPv6([::0]:123)和主机名(my.host.com:123).

无意中,此解决方案非常适合我的场景.无论如何,我打算使用URI方案.

  • 请注意,这也适用于其他一些事情,例如:"my:// foo:bar:baz /"或"my://something@foo.bar:8000 /"等...可能或者在你的情况下可能不是问题,但并不能真正满足原始问题避免"导致意外结果"的事情的愿望.:) (2认同)

cle*_*tus 8

正则表达式会非常巧妙地做到这一点:

Pattern p = Pattern.compile("^\\s*(.*?):(\\d+)\\s*$");
Matcher m = p.matcher("127.0.0.1:8080");
if (m.matches()) {
  String host = m.group(1);
  int port = Integer.parseInt(m.group(2));
}
Run Code Online (Sandbox Code Playgroud)

您可以通过多种方式实现此目的,例如使端口可选或在主机上进行一些验证.


Edw*_*ale 7

它没有完全回答这个问题,但是这个答案对于像我这样只想解析主机和端口的其他人来说仍然是有用的,但不一定是完整的InetAddress.Guava有一个HostAndPort类和一个parseString方法.


PSp*_*eed 6

另一个人给出了一个正则表达式的答案,这是我在最初询问有关主机的问题时正在做的事情.我仍然会这样做,因为它是一个更高级的正则表达式的例子,可以帮助确定你正在处理什么样的地址.

String ipPattern = "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}):(\\d+)";
String ipV6Pattern = "\\[([a-zA-Z0-9:]+)\\]:(\\d+)";
String hostPattern = "([\\w\\.\\-]+):(\\d+)";  // note will allow _ in host name
Pattern p = Pattern.compile( ipPattern + "|" + ipV6Pattern + "|" + hostPattern );
Matcher m = p.matcher( someString );
if( m.matches() ) {
    if( m.group(1) != null ) {
        // group(1) IP address, group(2) is port
    } else if( m.group(3) != null ) {
        // group(3) is IPv6 address, group(4) is port            
    } else if( m.group(5) != null ) {
        // group(5) is hostname, group(6) is port
    } else {
        // Not a valid address        
    }
}
Run Code Online (Sandbox Code Playgroud)

修改以使端口是可选的非常简单.将":(\d +)"换成"(?::(\ d +))?" 然后检查组(2)等的null.

编辑:我会注意到我没有"共同的方式"方式,但如果必须的话,上面就是我的方式.

另请注意:如果主机和IPv4实例的处理方式相同,则可以删除IPv4案例.我把它们分开了,因为如果你知道你有IP地址,有时你可以避免最终的主机查询.