Java:验证并将“主机:端口”转换为 InetSocketAddress 的常用方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2345063/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java: Common way to validate and convert "host:port" to InetSocketAddress?
提问by java.is.for.desktop
What is the common way in Java to validate and convert a string of the form host:port
into an instance of InetSocketAddress
?
Java 中验证表单字符串并将其转换host:port
为 的实例的常用方法是InetSocketAddress
什么?
It would be nice if following criteria were met:
如果满足以下条件就好了:
No address lookups;
Working for IPv4, IPv6, and "string" hostnames;
(For IPv4 it'sip:port
, for IPv6 it's[ip]:port
, right? Is there some RFC which defines all these schemes?)Preferable without parsing the string by hand.
(I'm thinking about all those special cases, when someone think he knows all valid forms of socket addresses, but forgets about "that special case" which leads to unexpected results.)
没有地址查找;
适用于 IPv4、IPv6 和“字符串”主机名;
(对于 IPv4 来说是ip:port
,对于 IPv6 来说是[ip]:port
,对吧?是否有一些 RFC 定义了所有这些方案?)最好不手动解析字符串。
(我正在考虑所有这些特殊情况,当有人认为他知道所有有效形式的套接字地址时,却忘记了导致意外结果的“那种特殊情况”。)
采纳答案by java.is.for.desktop
I myself propose one possible workaround solution.
我自己提出了一种可能的解决方法。
Convert a string into URI (this would validate it automatically) and then query the URI's host and port components.
将字符串转换为 URI(这会自动验证它),然后查询 URI 的主机和端口组件。
Sadly, an URI with a host component MUST have a scheme. This is why this solution is "not perfect".
可悲的是,带有主机组件的 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
}
This solution needs no custom string parsing, works with IPv4(1.1.1.1:123
), IPv6([::0]:123
) and host names(my.host.com:123
).
此解决方案不需要自定义字符串解析,适用于IPv4( 1.1.1.1:123
)、IPv6( [::0]:123
) 和主机名( my.host.com:123
)。
Accidentally, this solution is well suited for my scenario. I was going to use URI schemes anyway.
顺便说一句,这个解决方案非常适合我的场景。无论如何,我打算使用 URI 方案。
回答by AFK
new InetSocketAddress(
addressString.substring(0, addressString.lastIndexOf(":")),
Integer.parseInt(addressString.substring(addressString.lastIndexOf(":")+1, addressString.length));
? I probably made some little silly mistake. and I'm assuming you just wanted a new InetSocketAddress object out of the String in only that format. host:port
? 我可能犯了一些愚蠢的错误。并且我假设您只需要该格式的 String 中的一个新 InetSocketAddress 对象。主机:端口
回答by cletus
A regex will do this quite neatly:
正则表达式会非常巧妙地做到这一点:
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));
}
You can this in many ways such as making the port optional or doing some validation on the host.
您可以通过多种方式实现这一点,例如将端口设为可选或在主机上进行一些验证。
回答by PSpeed
Another person has given a regex answer which is what I was doing to do when originally asking the question about hosts. I will still do because it's an example of a regex that is slightly more advanced and can help determine what kind of address you are dealing with.
另一个人给出了一个正则表达式答案,这就是我最初询问有关主机的问题时要做的事情。我仍然会这样做,因为它是一个稍微更高级的正则表达式示例,可以帮助确定您正在处理的地址类型。
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
}
}
Modifying so that port is optional is pretty straight forward. Wrap the ":(\d+)" as "(?::(\d+))?" and then check for null for group(2), etc.
修改端口是可选的非常简单。将 ":(\d+)" 包裹为 "(?::(\d+))?" 然后检查组(2)等是否为空。
Edit: I'll note that there's no "common way" way that I'm aware of but the above is how I'd do it if I had to.
编辑:我会注意到没有我所知道的“通用方式”方式,但以上是我必须要做的事情。
Also note: the IPv4 case can be removed if the host and IPv4 cases will actually be handled the same. I split them out because sometimes you can avoid an ultimate host look-up if you know you have the IP address.
另请注意:如果主机和 IPv4 案例实际处理相同,则可以删除 IPv4 案例。我将它们分开是因为有时如果您知道自己拥有 IP 地址,就可以避免最终的主机查找。
回答by Edward Dale
It doesn't answer the question exactly, but this answer could still be useful others like me who just want to parse a host and port, but not necessarily a full InetAddress
. Guava has a HostAndPortclass with a parseString
method.
它并没有完全回答这个问题,但是这个答案对于像我这样只想解析主机和端口但不一定是完整的InetAddress
. Guava 有一个带有方法的HostAndPort类parseString
。
回答by Robin Davies
All kind of peculiar hackery, and elegant but unsafe solutions provided elsewhere. Sometimes the inelegant brute-force solution is the way.
其他地方提供的各种奇特的黑客技术和优雅但不安全的解决方案。有时,不优雅的蛮力解决方案就是这样。
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);
}
回答by Sean F
The open-source IPAddress Java libraryhas a HostNameclass which will do the required parsing. Disclaimer: I am the project manager of the IPAddress library.
在开源的ip地址的Java库有一个主机名类会做必要的分析。免责声明:我是 IPAddress 库的项目经理。
It will parse IPv4, IPv6 and string host names with or without ports. It will handle all the various formats of hosts and addresses. BTW, there is no single RFC for this, there are a number of RFCs that apply in different ways.
它将解析带有或不带有端口的 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
}