socket read library getoutputstream java networking sockets hostname ports

read - Java: ¿Una forma común de validar y convertir "host: port" a InetSocketAddress?



socket server java (6)

¿Cuál es la forma común en Java para validar y convertir una cadena del formulario host:port en una instancia de InetSocketAddress ?

Sería bueno si se cumplieran los siguientes criterios:

  • Sin búsquedas de direcciones;

  • Trabajando para nombres de host IPv4, IPv6 y "string";
    (Para IPv4 es ip:port , para IPv6 es [ip]:port , ¿verdad? ¿Hay algún RFC que defina todos estos esquemas?)

  • Preferible sin analizar la cadena a mano.
    (Estoy pensando en todos esos casos especiales, cuando alguien piensa que conoce todas las formas válidas de direcciones de socket, pero se olvida de "ese caso especial" que conduce a resultados inesperados).


No responde exactamente la pregunta, pero esta respuesta podría ser útil para otros como yo que solo quieren analizar un host y un puerto, pero no necesariamente una InetAddress completa. Guava tiene una clase HostAndPort con un método parseString .


Otra persona ha dado una respuesta de expresiones regulares, que es lo que estaba haciendo cuando originalmente hacía la pregunta sobre los hosts. Todavía lo haré porque es un ejemplo de una expresión regular que es un poco más avanzada y puede ayudar a determinar qué tipo de dirección está tratando.

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

La modificación para que el puerto sea opcional es bastante sencillo. Ajustar el ": (/ d +)" como "(? :: (/ d +))?" y luego verificar nulo para el grupo (2), etc.

Editar: Notaré que no hay una forma de "vía común" de la que sea consciente, pero lo anterior es cómo lo haría si tuviera que hacerlo.

También tenga en cuenta que el caso de IPv4 se puede eliminar si el host y los casos de IPv4 se manejarán de la misma manera. Los dividí porque a veces se puede evitar una última búsqueda de host si sabes que tienes la dirección IP.


Todo tipo de hackers peculiares y soluciones elegantes pero inseguras proporcionadas en otros lugares. A veces, la solución poco elegante de la fuerza bruta es el camino.

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


Una expresión regular lo hará bastante bien:

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

Puede hacerlo de muchas maneras, como hacer que el puerto sea opcional o realizar alguna validación en el host.


Yo mismo propongo una posible solución alternativa.

Convierta una cadena en URI (esto lo validaría automáticamente) y luego consulte los componentes de host y puerto del URI.

Lamentablemente, un URI con un componente de host DEBE tener un esquema. Esta es la razón por la cual esta solución "no es perfecta".

String string = ... // some string which has to be validated String host; int port; try { // WORKAROUND: add any scheme to make the resulting URI valid. URI uri = new URI("my://" + string); // may throw URISyntaxException host = uri.getHost(); 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, ... } catch (URISyntaxException ex) { // validation failed } // validation succeeded

Esta solución no necesita análisis de cadenas personalizadas , funciona con IPv4 ( 1.1.1.1:123 ), IPv6 ( [::0]:123 ) y nombres de host ( my.host.com:123 ).

Accidentalmente, esta solución es adecuada para mi escenario. Iba a usar esquemas de URI de todos modos.


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

? Probablemente cometí un pequeño error tonto. y asumo que solo quería un nuevo objeto InetSocketAddress fuera de la Cadena en solo ese formato. Puerto host