Java的:常见的方法来验证和转换“主机:端口”来的InetSocketAddress?

问题描述 投票:27回答:7

什么是在Java中常见的方式来验证和形式host:port的字符串转换成InetSocketAddress的实例?

如果以下条件得到满足这将是不错:

  • 没有地址查找;
  • 工作对IPv4,IPv6和“串”主机名; (对于IPv4是ip:port,对IPv6是[ip]:port,对不对?有没有一些RFC定义所有这些计划?)
  • 最好,而无需手动解析字符串。 (我在考虑所有这些特殊情况下,当有人认为他知道套接字地址的所有有效形式,但忘掉这会导致意想不到的结果“特殊情况”。)
java networking sockets hostname ports
7个回答
47
投票

我自己提出了一个可能的解决方法解决方案。

将一个字符串转换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
}

该解决方案无需自定义字符串解析,在IPv4(1.1.1.1:123),IPv6的([::0]:123)和主机名(my.host.com:123)的作品。

一不留神,这种解决方案非常适合我的方案。我还是要用URI方案。


9
投票

regex将做到这一点很整齐:

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));
}

你可以在这等多种方式使端口可选或做主机上的一些验证。


6
投票

它不回答这个问题完全是,但是这个答案可能仍然是有用的人喜欢我,谁只是想解析主机和端口,但不一定是一个完整的InetAddress。番石榴有一个HostAndPort方法parseString类。


5
投票

另一个人给了一个正则表达式的答案是我在做什么,当最初询问主机的问题做。我仍然会做,因为它是一个正则表达式是稍微更先进,可以帮助确定你正在处理什么样的地址的一个例子。

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        
    }
}

修饰使得端口可选是非常直接的。包裹 “:(\ d +)” 作为 “(?::(\ d +))?”然后检查空为基团(2)等

编辑:我注意到,有没有“共同方式”的方式,我所知道的,但上面的是我怎么会做,如果我不得不。

另外请注意:如果主机和IPv4的情况下实际上将被处理的同一IPv4的情况下,可以删除。我分裂出来,因为有时你能避免最终的主机查找,如果你知道你的IP地址。


2
投票
new InetSocketAddress(
  addressString.substring(0, addressString.lastIndexOf(":")),
  Integer.parseInt(addressString.substring(addressString.lastIndexOf(":")+1, addressString.length));

?我大概做了一些小愚蠢的错误。和我假设你只是想要一个新的InetSocketAddress对象了String的只是格式。主持人:端口


0
投票

所有类型的特殊两轮牛车,和其他地方提供优雅,但不安全的解决方案。有时不雅蛮力解决方案是这样的。

public static InetSocketAddress parseInetSocketAddress(String addressAndPort) throws IllegalArgumentException {
    int portPosition = addressAndPort.length();
    int portNumber = 0;
    while (portPosition > 1 && Character.isDigit(addressAndPort.charAt(portPosition-1)))
    {
        --portPosition;
    }
    String address;
    if (portPosition > 1 && addressAndPort.charAt(portPosition-1) == ':')
    {
        try {
            portNumber = Integer.parseInt(addressAndPort.substring(portPosition));
        } catch (NumberFormatException ignored)
        {
            throw new IllegalArgumentException("Invalid port number.");
        }
        address = addressAndPort.substring(0,portPosition-1);
    } else {
        portNumber = 0;
        address = addressAndPort;
    }
    return new InetSocketAddress(address,portNumber);
}

0
投票

open-source IPAddress Java libraryHostName类会做必要的分析。免责声明:我的ip地址库的项目经理。

它将分析的IPv4,IPv6和字符串主机名带或不带端口。它会处理的主机和地址的所有的各种格式。顺便说一句,对于这个没有单一的RFC,也有许多不同的方式适用RFC的。

String hostName = "[a:b:c:d:e:f:a:b]:8080";
String hostName2 = "1.2.3.4:8080";
String hostName3 = "a.com:8080";
try {
    HostName host = new HostName(hostName);
    host.validate();
    InetSocketAddress address = host.asInetSocketAddress();
    HostName host2 = new HostName(hostName2);
    host2.validate();
    InetSocketAddress address2 = host2.asInetSocketAddress();
    HostName host3 = new HostName(hostName3);
    host3.validate();
    InetSocketAddress address3 = host3.asInetSocketAddress();
    // use socket address      
} catch (HostNameException e) {
    String msg = e.getMessage();
    // handle improperly formatted host name or address string
}
© www.soinside.com 2019 - 2024. All rights reserved.