Pergunta

Debaixo IPv4 Eu tenho analisado a representação de string de endereços IP para Int32 e armazená -los como INT no SQL Server.

Agora com IPv6 Estou tentando descobrir se há uma maneira padrão ou aceita para analisar a representação de string de IPv6 para dois Int64 usando C#?

Também como as pessoas estão armazenando esses valores no SQL Server - Como dois campos de BIGINT?

Foi útil?

Solução

Assim como um endereço IPv4 é realmente um número de 32 bits, um endereço IPv6 é realmente um número de 128 bits. Existem diferentes representações de string dos endereços, mas o endereço real é o número, não a string.

Portanto, você não converte um endereço IP em um número, analisa uma representação de string do endereço no endereço real.

Nem mesmo um decimal Pode conter um número de 128 bits, para deixar três alternativas óbvias:

  • Armazene o valor numérico dividido em dois bigint Campos
  • Armazene uma representação de string do endereço em um varchar campo
  • Armazene o valor numérico em um byte de 16 binary campo

Nem é tão conveniente quanto armazenar um endereço IPv4 em um int, então você deve considerar as limitações deles contra o que precisa fazer com os endereços.

Outras dicas

A rota mais simples é fazer com que a estrutura faça isso por você. Usar IPAddress.Parse para analisar o endereço, então IPAddress.GetAddressBytes Para obter o "número" como byte [].

Finalmente, divida a matriz em primeiro e segundo 8 bytes para conversão em dois INT64s, por exemplo, criando um MemoryStream sobre a matriz de bytes e depois lendo através de um BinaryReader.

Isso evita a necessidade de entender todas as representações de atalho disponíveis para endereços IPv6.

Se você estiver usando o SQL Server 2005, pode usar o uniqueidentifier modelo. Este tipo armazena 16 bytes, o que é perfeito para um endereço IP IPv6. Você pode converter entre IPAddress e Guid usando os construtores e ToByteArray.

Eu uso o seguinte método para converter um endereço IP em dois UInt64s (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;
}

Certifique -se de lançar seu UInt64s para Int64s antes de colocá -los no banco de dados, ou você receberá um ArgumentException. Quando você retirar seus valores de volta, você pode lançá -los de volta para UInt64 para obter o valor não assinado.

Eu não tenho necessidade de fazer o contrário (ou seja, converter um UInt64[2] para uma string IP), então eu nunca criei um método para isso.

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']);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top