2009-04-21 44 views
19

Dưới IPv4 Tôi đã phân tích chuỗi đại diện của địa chỉ IP thành Int32 và lưu trữ chúng dưới dạng INT trong SQL Server.Định dạng IPv6 dưới dạng int trong C# và lưu trữ nó trong SQL Server

Bây giờ, với IPv6 Tôi đang cố gắng tìm hiểu xem có cách nào tiêu chuẩn hoặc được chấp nhận để phân tích cú pháp đại diện chuỗi IPv6 thành hai Int64 sử dụng C#?

Ngoài ra, cách mọi người lưu trữ các giá trị đó trong SQL Server - dưới dạng hai trường của BIGINT?

Trả lời

17

Cũng giống như địa chỉ IPv4 thực sự là số 32 bit, địa chỉ IPv6 thực sự là số 128 bit. Có các biểu diễn chuỗi khác nhau của các địa chỉ, nhưng địa chỉ thực tế là số, chứ không phải chuỗi.

Vì vậy, bạn không chuyển đổi địa chỉ IP thành một số, bạn phân tích cú pháp biểu diễn chuỗi địa chỉ thành địa chỉ thực.

Thậm chí một decimal có thể tổ chức một số 128 bit, do đó lá ba lựa chọn thay thế rõ ràng:

  • cửa hàng giá trị chia số thành hai bigint lĩnh vực
  • cửa hàng một chuỗi đại diện của địa chỉ trong một varchar lĩnh vực
  • cửa hàng giá trị số trong một byte 16 binary lĩnh vực

N hoặc là thuận tiện như lưu trữ một địa chỉ IPv4 trong một int, vì vậy bạn phải xem xét những hạn chế của họ chống lại những gì bạn cần làm với các địa chỉ.

+2

@ Bill: Bạn đang nhầm lẫn. Không có gì mà nói rằng bạn phải lưu trữ các byte của một địa chỉ IPv4 trong một giá trị unsigned. Int32 có 32 bit giống như UInt32, vì vậy nó hoạt động tốt để lưu trữ bốn byte. – Guffa

+0

Điều tốt @RBarryYoung không tìm thấy chủ đề này ;-) http://stackoverflow.com/a/1385701/215068 IPv4 là 4 byte nhị phân, không phải "thực sự là một số 32 bit". Bốn octet ba chữ số chỉ là một ký hiệu thuận tiện – EBarr

+0

@EBarr: Không, số IP trong phiên bản 4 * là * một số 32 bit, nó không phải là số 4 byte. Hãy xem mô tả về gói IP và bạn thấy rằng các địa chỉ là các đơn vị đơn 32 bit, chúng không được tách thành bốn giá trị 8 bit. – Guffa

10

Tuyến đường đơn giản nhất là tạo khung làm việc này cho bạn. Sử dụng IPAddress.Parse để phân tích cú pháp địa chỉ, sau đó IPAddress.GetAddressBytes để lấy "số" làm byte [].

Cuối cùng, chia mảng thành 8 byte đầu tiên và thứ hai để chuyển đổi thành hai Int64, ví dụ: bằng cách tạo một MemoryStream trên mảng byte và sau đó đọc qua BinaryReader.

Điều này tránh phải hiểu tất cả các đại diện cắt ngắn sẵn có cho địa chỉ IPv6.

+0

lý do tại sao 2 int64 thay vì trường nhị phân (128)? – Henry

+0

@ Henry: Đó là những gì Q được chỉ định. – Richard

3

Tôi sử dụng phương pháp sau để chuyển đổi địa chỉ IP thành hai 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; 
} 

Hãy chắc chắn rằng bạn cast UInt64 của bạn để Int64 s trước khi bạn đặt chúng vào cơ sở dữ liệu, hoặc bạn sẽ nhận được một ArgumentException. Khi bạn lấy lại các giá trị của mình, bạn có thể truyền trở lại UInt64 để nhận giá trị chưa ký.

Tôi không cần phải làm ngược lại (tức là chuyển đổi UInt64[2] thành chuỗi IP) để tôi không bao giờ tạo phương thức cho nó.

+0

Không có nhiều trường hợp bạn muốn lưu trữ 255.255.255.255 hoặc FFFF: FFFF: FFFF: FFFF: FFFF: FFFF: FFFF: FFFF. – Gavin

+1

-1: Int32 hoạt động tốt để lưu trữ địa chỉ IPv4. Bạn đang nhìn chằm chằm vào giá trị tối đa của số nguyên, nhưng điều đó không liên quan. 32 bit là 32 bit và rõ ràng là đủ để biểu diễn bốn byte của địa chỉ IPv4. – Guffa

+0

Tệ của tôi. Tôi nghĩ rằng CLR sẽ ném một lỗi tràn thay vì "đi quanh góc" khi cố gắng để đúc UInt32.MaxValue đến một Int32. Tôi đã chỉnh sửa câu trả lời của mình để phản ánh điều đó. –

4

Nếu bạn đang sử dụng SQL Server 2005, bạn có thể sử dụng loại uniqueidentifier. Loại này lưu trữ 16 byte, đó là hoàn hảo cho một địa chỉ ip IPv6. Bạn có thể chuyển đổi giữa các số IPAddressGuid bằng cách sử dụng các hàm tạo và ToByteArray.

+4

Sự cố với 'uniqueidentifier' là bạn không thể thực hiện tìm kiếm theo phạm vi. I E. bạn không thể tìm kiếm một dải IP có chứa một IP cụ thể. Chúng tôi đã thử điều này với một bảng ** 3.000.000 ** hàng dữ liệu. Và thay vì dẫn đến kết quả 3 hàng, chúng tôi nhận được ** ~ 73.000 ** hàng – 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

Đây là PHP, OP cho biết C# – nokturnal

Các vấn đề liên quan