it-swarm.com.de

Java: Gängige Methode zum Validieren und Konvertieren von "Host: Port" in InetSocketAddress?

Was ist die übliche Methode in Java, um einen String der Form Host:port in eine Instanz von InetSocketAddress zu validieren und zu konvertieren?

Es wäre schön, wenn folgende Kriterien erfüllt wären:

  • Keine Adresssuche;

  • Arbeiten für IPv4-, IPv6- und String-Hostnamen;
    (Für IPv4 ist es ip:port, für IPv6 ist es [ip]:port, oder? Gibt es einen RFC, der alle diese Schemata definiert?)

  • Am besten ohne die Zeichenkette von Hand zu analysieren.
    (Ich denke über all diese Sonderfälle nach, wenn jemand glaubt, alle gültigen Socket-Adressen zu kennen, vergisst aber "diesen Sonderfall", der zu unerwarteten Ergebnissen führt.)

27

Ich selbst schlage eine mögliche Lösung für die Problemumgehung vor.

Konvertieren Sie eine Zeichenfolge in eine URI (dies würde sie automatisch überprüfen), und fragen Sie dann die Host- und Port-Komponenten der URI ab.

Leider muss eine URI mit einer Host-Komponente ein Schema haben. Deshalb ist diese Lösung "nicht perfekt".

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
}

Diese Lösung erfordert keine benutzerdefinierte Zeichenfolgenanalyse funktioniert mit IPv4 (1.1.1.1:123), IPv6 ([::0]:123) und Hostnamen (my.Host.com:123).

Diese Lösung ist aus Versehen gut für mein Szenario geeignet. Ich würde sowieso URI-Schemata verwenden.

44

Ein Regex tut das ganz ordentlich:

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

Sie können dies auf viele Arten tun, z. B. indem Sie den Port optional machen oder eine Validierung auf dem Host durchführen.

8
cletus

Es beantwortet die Frage nicht genau, aber diese Antwort könnte nützlich sein, andere wie ich, die nur einen Host und einen Port analysieren wollen, aber nicht unbedingt eine vollständige InetAddress. Guava besitzt eine HostAndPort -Klasse mit einer parseString-Methode.

6
Edward Dale

Eine andere Person hat eine Regex-Antwort gegeben. Dies ist, was ich getan habe, als ich ursprünglich die Frage nach Gastgebern stellte. Ich werde es immer noch tun, weil dies ein Beispiel für einen Regex ist, der etwas fortgeschrittener ist und dabei helfen kann festzustellen, mit welcher Art von Adresse Sie sich befassen.

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

Das Ändern des Ports ist optional. Wickeln Sie das ": (\ d +)" in "(? :: (\ d +))?" und dann nach Null für Gruppe (2) usw. suchen.

Edit: Ich werde feststellen, dass es keinen "üblichen Weg" gibt, den ich kenne, aber wie oben beschrieben würde ich es tun, wenn ich müsste.

Beachten Sie auch: Der IPv4-Fall kann entfernt werden, wenn der Host- und der IPv4-Fall tatsächlich gleich behandelt werden. Ich spalte sie auf, weil Sie manchmal eine ultimative Host-Suche vermeiden können, wenn Sie wissen, dass Sie die IP-Adresse haben.

5
PSpeed
new InetSocketAddress(
  addressString.substring(0, addressString.lastIndexOf(":")),
  Integer.parseInt(addressString.substring(addressString.lastIndexOf(":")+1, addressString.length));

? Ich habe wahrscheinlich einen kleinen dummen Fehler gemacht. und ich gehe davon aus, dass Sie nur ein neues InetSocketAddress-Objekt aus dem String in diesem Format haben wollten. Host: Port

2
AFK

Die Open-Source-IPAddress-Java-Bibliothek hat eine HostName -Klasse, die die erforderliche Analyse durchführt. Haftungsausschluss: Ich bin der Projektmanager der IPAddress-Bibliothek. 

Es werden IPv4-, IPv6- und String-Hostnamen mit oder ohne Ports analysiert. Es werden alle verschiedenen Formate von Hosts und Adressen behandelt. Übrigens, es gibt keinen einzigen RFC dafür, es gibt eine Reihe von RFCs, die auf unterschiedliche Weise gelten.

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

Alle Arten von eigenartigen Hackereien und elegante, aber unsichere Lösungen, die an anderer Stelle angeboten werden. Manchmal ist die unelegante Brute-Force-Lösung der Weg.

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