Java: общий способ проверки и преобразования "host: port" в InetSocketAddress? - PullRequest
27 голосов
/ 27 февраля 2010

Каков обычный способ в Java для проверки и преобразования строки вида host:port в экземпляр InetSocketAddress?

Было бы неплохо, если бы были выполнены следующие критерии:

  • Нет поиска адресов;

  • Работа для имен хостов IPv4, IPv6 и "string";
    (Для IPv4 это ip:port, для IPv6 это [ip]:port, верно? Есть какой-то RFC, который определяет все эти схемы?)

  • Желательно без разбора строки вручную.
    (Я имею в виду все эти особые случаи, когда кто-то думает, что он знает все действительные формы адресов сокетов, но забывает о «этом особом случае», который приводит к неожиданным результатам.)

Ответы [ 7 ]

46 голосов
/ 27 февраля 2010

Я сам предлагаю одно возможное обходное решение.

Преобразуйте строку в 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 голосов
/ 27 февраля 2010

регулярное выражение сделает это довольно аккуратно:

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 голосов
/ 27 ноября 2012

Он не дает точного ответа на этот вопрос, но этот ответ может быть полезен другим, таким как я, которые просто хотят проанализировать хост и порт, но не обязательно полные InetAddress. В Guava есть класс HostAndPort с методом parseString.

5 голосов
/ 27 февраля 2010

Другой человек дал ответ на регулярное выражение, что я и делал, когда первоначально задавал вопрос о хостах.Я все еще буду делать, потому что это пример регулярного выражения, которое немного более продвинутое и может помочь определить, с каким типом адреса вы имеете дело.Оберните ": (\ d +)" как "(? :: (\ d +))?"а затем проверьте нулевое значение для группы (2) и т. д.

Редактировать: я отмечу, что я не знаю «общего пути», но вышеизложенное - как я это сделаюМне пришлось.

Также обратите внимание: случай IPv4 может быть удален, если случаи хоста и IPv4 будут фактически обрабатываться одинаково.Я разделил их, потому что иногда вы можете избежать окончательного поиска хоста, если знаете, что у вас есть IP-адрес.

2 голосов
/ 27 февраля 2010
new InetSocketAddress(
  addressString.substring(0, addressString.lastIndexOf(":")),
  Integer.parseInt(addressString.substring(addressString.lastIndexOf(":")+1, addressString.length));

? Я, вероятно, сделал небольшую глупую ошибку. и я предполагаю, что вы просто хотели новый объект InetSocketAddress из строки только в этом формате. хост: порт

0 голосов
/ 06 января 2019

Java-библиотека с открытым исходным кодом имеет класс 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 голосов
/ 23 июля 2018

Все виды своеобразных хакерских атак и элегантные, но небезопасные решения, представленные в других местах Иногда неумелое решение грубой силы - путь.

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