سؤال

تحت IPv4 لقد قمت بتحليل تمثيل سلسلة عناوين IP Int32 وتخزينها كما INT في ال SQL Server.

الان مع IPv6 أحاول معرفة ما إذا كان هناك طريقة قياسية أو مقبولة لتحليل تمثيل سلسلة IPv6 الى اثنين Int64 استخدام C#?

أيضا كيف يخزن الناس تلك القيم في SQL Server - كحافظين من BIGINT?

هل كانت مفيدة؟

المحلول

تماما مثل عنوان IPv4 هو حقا رقم 32 بت، فإن عنوان IPv6 هو حقا رقم 128 بت. هناك تمثيلات سلسلة مختلفة للعناوين، ولكن العنوان الفعلي هو الرقم، وليس السلسلة.

لذلك، لا تقوم بتحويل عنوان IP إلى رقم، تحليل تمثيل سلسلة من العنوان في العنوان الفعلي.

ليس حتى decimal يمكن أن تعقد رقم 128 بت، بحيث يترك ثلاثة بدائل واضحة:

  • تخزين القيمة الرقمية تقسيم إلى اثنين bigint مجالات
  • تخزين تمثيل سلسلة من العنوان في varchar حقل
  • تخزين القيمة الرقمية في 16 بايت binary حقل

لا هو مناسب مثل تخزين عنوان IPv4 في int, ، لذلك عليك أن تنظر في حدودها ضد ما عليك القيام به مع العناوين.

نصائح أخرى

أبسط الطريق هو الحصول على الإطار للقيام بذلك من أجلك. يستخدم IPAddress.Parse لتحليل العنوان، ثم IPAddress.GetAddressBytes للحصول على "الرقم" كما BYTE [].

أخيرا، قسم الصفيف إلى 8 بايت 8 الأولى والثانية للتحويل إلى اثنين من 64s، على سبيل المثال عن طريق إنشاء MemoryStream على صفيف البايت ثم القراءة عبر BinaryReader.

يتجنب ذلك الحاجة إلى فهم جميع تمثيلات المختصرة المتاحة لعناوين IPv6.

إذا كنت تستخدم SQL Server 2005، يمكنك استخدام uniqueidentifier اكتب. يخزن هذا النوع 16 بايت، وهو مثالي لعنوان IP IPv6. يمكنك التحويل بين IPAddress و Guid باستخدام المنشئين و ToByteArray.

يمكنني استخدام الطريقة التالية لتحويل عنوان IP إلى اثنين 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;
}

تأكد من أن يلقي بك UInt64ب Int64ق قبل وضعها في قاعدة البيانات، أو ستحصل على ArgumentException. وبعد عندما تحصل على قيمك مرة أخرى، يمكنك إلقاءها مرة أخرى UInt64 للحصول على القيمة غير الموقعة.

ليس لدي حاجة للقيام بالعكس (أي تحويل UInt64[2] إلى سلسلة IP) لذلك لم أبدت طريقة لذلك.

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']);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top