2009-04-21 16 views
19

Bajo IPv4 que se han de análisis la representación de cadena de direcciones IP a Int32 y su almacenamiento como en el INTSQL Server.El formato IPv6 como un int en C# y su almacenamiento en SQL Server

Ahora, con IPv6 estoy tratando de averiguar si hay una forma estándar o aceptado para analizar la representación de cadena de IPv6 a dos Int64 usando C#?

También, ¿cómo se almacenan las personas esos valores en el SQL Server - como dos campos de BIGINT?

Respuesta

17

Al igual que una dirección IPv4 es realmente un número de 32 bits, una dirección IPv6 es realmente un número de 128 bits. Hay diferentes representaciones de cadenas de las direcciones, pero la dirección real es el número, no la cadena.

Por lo tanto, no convierte una dirección IP a un número, analiza una representación en cadena de la dirección en la dirección real.

Ni siquiera un decimal puede contener un número de 128 bits, por lo que deja tres alternativas obvias:

  • tienda el valor de división numérica en dos bigint campos
  • tienda de una cadena que representa la dirección en un varchar campo
  • tienda el valor numérico en un byte 16 binary campo

N cualquiera es tan conveniente como almacenar una dirección IPv4 en un int, por lo que debe tener en cuenta sus limitaciones con respecto a lo que debe hacer con las direcciones.

+2

@ Bill: Usted está equivocado. No hay nada que diga que debe almacenar los bytes de una dirección IPv4 en un valor sin signo. Un Int32 tiene 32 bits como un UInt32, por lo que funciona perfectamente para almacenar cuatro bytes. – Guffa

+0

Lo bueno @RBarryYoung no encontró este hilo ;-) http://stackoverflow.com/a/1385701/215068 IPv4 es de 4 bytes binarios, no "realmente un número de 32 bits". Los cuatro octetos de tres dígitos son solo una notación conveniente – EBarr

+0

@EBarr: No, el número de IP en la versión 4 * es * un número de 32 bits, no es un número de 4 bytes. Mire una descripción del paquete IP, y verá que las direcciones son unidades únicas de 32 bits, no están separadas en cuatro valores de 8 bits. – Guffa

10

La ruta más simple es hacer que el marco haga esto por usted. Use IPAddress.Parse para analizar la dirección, luego IPAddress.GetAddressBytes para obtener el "número" como byte [].

Finalmente, divida la matriz en el primer y segundo 8 bytes para la conversión a dos Int64, p. Ej. creando un MemoryStream sobre el conjunto de bytes y luego leyendo a través de un BinaryReader.

Esto evita tener que entender todas las representaciones de acceso directo disponibles para direcciones IPv6.

+0

¿por qué 2 int64 en lugar de campo binario (128)? – Henry

+0

@Henry: Eso es lo que especificó la Q. – Richard

3

Utilizo el siguiente método para convertir una dirección IP a dos UInt64 s (C# 3.0).

/// <summary> 
/// Converts an IP address to its UInt64[2] equivalent. 
/// For an IPv4 address, the first element will be 0, 
/// and the second will be a UInt32 representation of the four bytes. 
/// For an IPv6 address, the first element will be a UInt64 
/// representation of the first eight bytes, and the second will be the 
/// last eight bytes. 
/// </summary> 
/// <param name="ipAddress">The IP address to convert.</param> 
/// <returns></returns> 
private static ulong[] ConvertIPAddressToUInt64Array(string ipAddress) 
{ 
    byte[] addrBytes = System.Net.IPAddress.Parse(ipAddress).GetAddressBytes(); 
    if (System.BitConverter.IsLittleEndian) 
    { 
     //little-endian machines store multi-byte integers with the 
     //least significant byte first. this is a problem, as integer 
     //values are sent over the network in big-endian mode. reversing 
     //the order of the bytes is a quick way to get the BitConverter 
     //methods to convert the byte arrays in big-endian mode. 
     System.Collections.Generic.List<byte> byteList = new System.Collections.Generic.List<byte>(addrBytes); 
     byteList.Reverse(); 
     addrBytes = byteList.ToArray(); 
    } 
    ulong[] addrWords = new ulong[2]; 
    if (addrBytes.Length > 8) 
    { 
     addrWords[0] = System.BitConverter.ToUInt64(addrBytes, 8); 
     addrWords[1] = System.BitConverter.ToUInt64(addrBytes, 0); 
    } 
    else 
    { 
     addrWords[0] = 0; 
     addrWords[1] = System.BitConverter.ToUInt32(addrBytes, 0); 
    } 
    return addrWords; 
} 

Asegúrese de emitir su UInt64 s a Int64 s antes de ponerlos en la base de datos, o que obtendrá una ArgumentException. Cuando recupere sus valores, puede devolverlos al UInt64 para obtener el valor sin firmar.

No necesito hacer lo contrario (es decir, convertir UInt64[2] en una cadena IP) así que nunca construí un método para ello.

+0

No hay muchos casos en los que alguna vez quiera almacenar 255.255.255.255 o FFFF: FFFF: FFFF: FFFF: FFFF: FFFF: FFFF: FFFF. – Gavin

+1

-1: Un Int32 funciona bien para almacenar una dirección IPv4. Estás mirando ciegamente el valor máximo del entero, pero eso es irrelevante. 32 bits son 32 bits y obviamente son suficientes para representar los cuatro bytes de una dirección IPv4. – Guffa

+0

Mi mal. Pensé que el CLR arrojaría un error de desbordamiento en lugar de "doblar la esquina" al intentar convertir UInt32.MaxValue en un Int32. He editado mi respuesta para reflejar eso. –

4

Si está utilizando SQL Server 2005, puede utilizar el tipo uniqueidentifier. Este tipo almacena 16 bytes, lo que es perfecto para una dirección IP IPv6. Puede convertir entre IPAddress y Guid utilizando los constructores y ToByteArray.

+4

El problema con 'uniqueidentifier' es que no puede hacer búsquedas de rango. Es decir. no puede buscar un rango de IP que contenga una IP específica. Probamos esto con una tabla de ** 3.000.000 ** filas de datos. Y en lugar de generar un resultado de 3 filas, obtuvimos ** ~ 73,000 ** filas – NoLifeKing

0
function encode_ip ($ip) 
{ 
    return bin2hex(inet_pton($ip)); 
} 

function decode_ip($ip) 
{ 
    function hex2bin($temp) { 
     $data=""; 
     for ($i=0; $i < strlen($temp); $i+=2) $data.=chr(hexdec(substr($temp,$i,2))); 
     return $data; 
    } 
    return inet_ntop(hex2bin($ip)); 
} 

-- max len row db 
echo strlen(inet_pton('2001:db8:85a3::8a2e:370:7334')); 

-- db row info 
ip varchar(16) 

-- sql binary save and read 
save base 
$bin_ip='0x'.bin2hex(inet_pton($data['ip_address'])); 

-- db read 
select ip_address from users; 

-- encode binary from db 
echo inet_ntop($row['ip_address']); 
+3

Esto es PHP, OP declara C# – nokturnal

Cuestiones relacionadas