2010-02-10 4 views
16

En utilisant les bibliothèques Java standard, quel est le moyen le plus rapide d'obtenir de la représentation en pointillés d'une adresse IPV4 ("127.0.0.1") à la représentation entière équivalente (2130706433).Passage de 127.0.0.1 à 2130706433 et retour

Et de manière correspondante, quel est le moyen le plus rapide d'inverser cette opération - en passant de l'entier 2130706433 à la représentation sous forme de chaîne "127.0.0.1"?

Répondre

25

Chaîne à int:

int pack(byte[] bytes) { 
    int val = 0; 
    for (int i = 0; i < bytes.length; i++) { 
    val <<= 8; 
    val |= bytes[i] & 0xff; 
    } 
    return val; 
} 

pack(InetAddress.getByName(dottedString).getAddress()); 

Int à chaîne:

byte[] unpack(int bytes) { 
    return new byte[] { 
    (byte)((bytes >>> 24) & 0xff), 
    (byte)((bytes >>> 16) & 0xff), 
    (byte)((bytes >>> 8) & 0xff), 
    (byte)((bytes  ) & 0xff) 
    }; 
} 


InetAddress.getByAddress(unpack(packedBytes)).getHostAddress() 
+2

127.0.0.1 donne 2130706433, mais 255.255.255.255 ne donne pas 4294967295. problème signé ou non signé? – knorv

+4

Pour imprimer en tant que non signé, le résultat est long et masque les bits élevés: '((long) packedBytes) & 0xffffffff' –

+0

octet en Java est jusqu'à 2^7-1 de sorte que chaque octet ne sera pas en mesure d'afficher tout nombre entier supérieur à 127. La bonne approche consiste à utiliser int pour stocker le chiffre. – zhaocong

2

Je ne l'ai pas essayé. performances, mais la façon la plus simple est probablement d'utiliser le NIO ByteBuffer.

par exemple.

byteBuffer.put(integer).array(); 

retournera un tableau d'octets représentant l'entier. Vous pouvez besoin de modifier l'ordre des octets.

+0

pourquoi ne pas simplement choisir un ordre d'octets et de le rendre l'ordre des octets du ByteBuffer? Vous n'aurez alors plus à vous soucier des différents ordres d'octets par défaut sur différentes machines. EDIT: nevermind, la valeur par défaut est Big endian. –

9

J'ai modifié ma réponse originale. Dans l'implémentation de Sun de InetAddress, la méthode hashCode produit la représentation en nombre entier de l'adresse IPv4, mais comme les commentateurs l'ont signalé à juste titre, cela n'est pas garanti par JavaDoc. Par conséquent, j'ai décidé d'utiliser la classe ByteBuffer pour calculer la valeur de l'adresse IPv4 à la place.

import java.net.InetAddress; 
import java.nio.ByteBuffer; 

// ... 

try { 
    // Convert from integer to an IPv4 address 
    InetAddress foo = InetAddress.getByName("2130706433"); 
    String address = foo.getHostAddress(); 
    System.out.println(address); 

    // Convert from an IPv4 address to an integer 
    InetAddress bar = InetAddress.getByName("127.0.0.1"); 
    int value = ByteBuffer.wrap(bar.getAddress()).getInt(); 
    System.out.println(value); 

} catch (Exception e) { 
    e.printStackTrace(); 
} 

La sortie sera:

127.0.0.1 
2130706433 
+1

Le hashCode() est-il bien défini comme faisant une conversion de 4 octets en int? Sinon, je soupçonne que c'est le cas. Une explication est toujours bonne, l'esprit. –

+0

La correspondance entre l'adresse IP et int doit être une bijection. hashCode ne le garantit pas. –

+0

Cela devrait être downvoted. Rien dans les Javadocs ne garantit ce comportement, il s'agit simplement de l'implémentation (raisonnable) de Sun pour le moment. Sun pourrait changer ceci pour juste renvoyer une constante et il se comporterait toujours correctement, mais votre exemple échouerait. –

3

Si vous avez besoin d'apprendre la longue main math, vous pouvez utiliser Substr pour ripper les octets. Mutliply le premier octet signifiant la classe par (256 * 256 * 256) ou (2^24) deuxième multiplié par (256 * 256) (2^16) troisième multiplié par (256) (2^8) quatrième multiplié par 1 ou (2^0)

127 * (2^24) + 0 * (2^16) + 0 * (2^8) + 1 * (2^0) 2130706432 + 0 + 0 + 1 = 2130706433

27

Vous pouvez également utiliser la classe Google Guava InetAddress

String ip = "192.168.0.1"; 
InetAddress addr = InetAddresses.forString(ip); 
// Convert to int 
int address = InetAddresses.coerceToInteger(addr); 
// Back to str 
String addressStr = InetAddresses.fromInteger(address)); 
+2

Je pense que c'est le plus simple. À moins que vous ne soyez préoccupé par les performances de la micro-seconde, utilisez les bibliothèques standard qui traitent tous les endians et les signes –

0

une autre façon:

public static long ipToLong(String ipAddress) { 

    String[] ipAddressInArray = ipAddress.split("\\."); 

    long result = 0; 
    for (int i = 0; i < ipAddressInArray.length; i++) { 

     int power = 3 - i; 
     int ip = Integer.parseInt(ipAddressInArray[i]); 
     result += ip * Math.pow(256, power); 

    } 

    return result; 
    } 
0

En utilisant the IPAddress Java library il est simple, une ligne de code pour chaque direction. Avis de non-responsabilité: Je suis le gestionnaire de projet de cette bibliothèque.

IPv4Address loopback = new IPAddressString("127.0.0.1").getAddress().toIPv4(); 
    System.out.println(loopback.intValue()); 
    IPv4Address backAgain = new IPv4Address(loopback.intValue()); 
    System.out.println(backAgain); 

Sortie:

2130706433 
    127.0.0.1 
Questions connexes