web-dev-qa-db-ja.com

Java:「Host:port」を検証してInetSocketAddressに変換する一般的な方法

JavaでHost:portという形式の文字列を検証してInetSocketAddressのインスタンスに変換する一般的な方法は何ですか?

以下の基準が満たされていればいいのですが。

  • アドレス検索はありません。

  • IPv4、IPv6、および「文字列」ホスト名で機能します。
    (IPv4の場合はip:port、IPv6の場合は[ip]:portですよね?これらのすべてのスキームを定義するRFCはありますか?)

  • 文字列を手動で解析せずに使用することをお勧めします。
    (ソケットアドレスのすべての有効な形式を知っていると誰かが思うとき、私はこれらすべての特別なケースについて考えていますが、予期しない結果につながる「その特別なケース」を忘れています。)

30

私自身、可能な回避策の1つを提案します。

文字列をURIに変換し(これにより自動的に検証されます)、URIのホストコンポーネントとポートコンポーネントを照会します。

悲しいことに、Hostコンポーネントを持つ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
}

このソリューションカスタム文字列の解析は必要ありませんIPv41.1.1.1:123)、IPv6[::0]:123)およびホスト名my.Host.com:123)。

偶然にも、このソリューションは私のシナリオに適しています。とにかくURIスキームを使用するつもりでした。

47

正規表現はこれを非常にきれいに行います:

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

これは、ポートをオプションにしたり、ホストで検証を行うなど、さまざまな方法で行うことができます。

9
cletus

それは質問に正確に答えるものではありませんが、この答えは、ホストとポートを解析したいだけの、必ずしも完全なInetAddressとは限らない、私のような他の人にも役立ちます。 Guavaには、parseStringメソッドを持つ HostAndPort クラスがあります。

6
Edward Dale
new InetSocketAddress(
  addressString.substring(0, addressString.lastIndexOf(":")),
  Integer.parseInt(addressString.substring(addressString.lastIndexOf(":")+1, addressString.length));

?たぶん、ちょっとばかげた間違いをしたでしょう。そして、あなたはそのフォーマットでのみStringから新しいInetSocketAddressオブジェクトが欲しかったと仮定しています。ホスト:ポート

2
AFK

open-source IPAddress Java library には、必要な解析を行う HostName クラスがあります。免責事項:私はプロジェクトマネージャーですIPAddressライブラリ。

ポートの有無にかかわらず、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
}
0
Sean F

あらゆる種類の特異なハッカー、エレガントで安全ではないソリューションが他の場所で提供されています。時々、無作法な総当たりの解決策が方法です。

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
Robin Davies