Tôi đang tìm kiếm một hàm sẽ chuyển đổi địa chỉ IPv4 chuẩn thành Số nguyên. Điểm thưởng có sẵn cho một chức năng sẽ làm điều ngược lại.
Giải pháp phải ở trong C #.
Tôi đang tìm kiếm một hàm sẽ chuyển đổi địa chỉ IPv4 chuẩn thành Số nguyên. Điểm thưởng có sẵn cho một chức năng sẽ làm điều ngược lại.
Giải pháp phải ở trong C #.
Câu trả lời:
Số nguyên không dấu 32-bit là địa chỉ IPv4. Trong khi đó, thuộc IPAddress.Address
tính, mặc dù không được dùng nữa, là một Int64 trả về giá trị 32-bit chưa được đánh dấu của địa chỉ IPv4 (bắt là, nó theo thứ tự byte mạng, vì vậy bạn cần phải hoán đổi nó).
Ví dụ: google.com địa phương của tôi tại 64.233.187.99
. Điều đó tương đương với:
64*2^24 + 233*2^16 + 187*2^8 + 99
= 1089059683
Và thực sự, http: // 1089059683 / hoạt động như mong đợi (ít nhất là trong Windows, được thử nghiệm với IE, Firefox và Chrome; mặc dù không hoạt động trên iPhone).
Đây là một chương trình thử nghiệm để hiển thị cả hai chuyển đổi, bao gồm hoán đổi byte mạng / máy chủ:
using System;
using System.Net;
class App
{
static long ToInt(string addr)
{
// careful of sign extension: convert to uint first;
// unsigned NetworkToHostOrder ought to be provided.
return (long) (uint) IPAddress.NetworkToHostOrder(
(int) IPAddress.Parse(addr).Address);
}
static string ToAddr(long address)
{
return IPAddress.Parse(address.ToString()).ToString();
// This also works:
// return new IPAddress((uint) IPAddress.HostToNetworkOrder(
// (int) address)).ToString();
}
static void Main()
{
Console.WriteLine(ToInt("64.233.187.99"));
Console.WriteLine(ToAddr(1089059683));
}
}
Dưới đây là một số phương pháp để chuyển đổi từ IPv4 thành một số nguyên chính xác và quay lại:
public static uint ConvertFromIpAddressToInteger(string ipAddress)
{
var address = IPAddress.Parse(ipAddress);
byte[] bytes = address.GetAddressBytes();
// flip big-endian(network order) to little-endian
if (BitConverter.IsLittleEndian)
{
Array.Reverse(bytes);
}
return BitConverter.ToUInt32(bytes, 0);
}
public static string ConvertFromIntegerToIpAddress(uint ipAddress)
{
byte[] bytes = BitConverter.GetBytes(ipAddress);
// flip little-endian to big-endian(network order)
if (BitConverter.IsLittleEndian)
{
Array.Reverse(bytes);
}
return new IPAddress(bytes).ToString();
}
Thí dụ
ConvertFromIpAddressToInteger("255.255.255.254"); // 4294967294
ConvertFromIntegerToIpAddress(4294967294); // 255.255.255.254
Giải trình
Địa chỉ IP theo thứ tự mạng (big-endian), trong khi int
s là little-endian trên Windows, vì vậy để nhận được giá trị chính xác, bạn phải đảo ngược các byte trước khi chuyển đổi trên hệ thống little-endian.
Ngoài ra, ngay cả đối với IPv4
, mộtint
không thể chứa các địa chỉ lớn hơn 127.255.255.255
, ví dụ địa chỉ quảng bá (255.255.255.255)
, vì vậy hãy sử dụng a uint
.
1.1.1.1
vì mảng byte của nó là palindromic. Hãy thử với những cái không phải palindromic như 127.0.0.1
hoặc 192.168.1.1
.
1.1.1.1
, 2.2.2.2
, 123.123.123.123
luôn mang lại kết quả tương tự. Đối với hậu thế, hãy xem cập nhật fiddle: dotnetfiddle.net/aR6fhc
System.Net.IPAddress
để làm cho nó hoạt động. Hoạt động tuyệt vời!
2.1.1.2
sẽ giống nhau.
@Barry Kelly và @Andrew Hare, thực ra, tôi không nghĩ rằng nhân là cách rõ ràng nhất để làm điều này (tất cả đều đúng).
Địa chỉ IP "được định dạng" Int32 có thể được xem như cấu trúc sau
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct IPv4Address
{
public Byte A;
public Byte B;
public Byte C;
public Byte D;
}
// to actually cast it from or to an int32 I think you
// need to reverse the fields due to little endian
Vì vậy, để chuyển đổi địa chỉ ip 64.233.187.99 bạn có thể làm:
(64 = 0x40) << 24 == 0x40000000
(233 = 0xE9) << 16 == 0x00E90000
(187 = 0xBB) << 8 == 0x0000BB00
(99 = 0x63) == 0x00000063
---------- =|
0x40E9BB63
vì vậy bạn có thể thêm chúng bằng cách sử dụng + hoặc bạn có thể binairy hoặc chúng cùng nhau. Kết quả là 0x40E9BB63 là 1089059683. (Theo ý kiến của tôi khi nhìn bằng hệ lục phân thì việc xem các byte sẽ dễ dàng hơn nhiều)
Vì vậy, bạn có thể viết hàm dưới dạng:
int ipToInt(int first, int second,
int third, int fourth)
{
return (first << 24) | (second << 16) | (third << 8) | (fourth);
}
LayoutKind.Explicit
và FieldOffset
đảo ngược thứ tự lưu trữ các byte. Tất nhiên, điều đó chỉ phù hợp với kiến trúc thời kỳ cuối. Ví dụ trên github .
int
được ký, vì vậy nếu bạn thay đổi 192 bằng 24 bit, bạn sẽ nhận được số nguyên âm vì vậy mã này bị hỏng đối với octet cao có bit cao ở vị trí đầu tiên.
Hãy thử những cái này:
private int IpToInt32(string ipAddress)
{
return BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes().Reverse().ToArray(), 0);
}
private string Int32ToIp(int ipAddress)
{
return new IPAddress(BitConverter.GetBytes(ipAddress).Reverse().ToArray()).ToString();
}
Reverse()
trả về void, do đó bạn không thể gọi ToArray()
nó (đối với những người đọc trong tương lai). Thay vào đó, hãy gán một giá trị cho các byte được đảo ngược, sau đó bạn có thể gọi ToArray ().
IEnumerable
. Mã trên là hoàn toàn ok.
Vì không ai đăng mã sử dụng BitConverter
và thực sự kiểm tra độ bền, đây là:
byte[] ip = address.Split('.').Select(s => Byte.Parse(s)).ToArray();
if (BitConverter.IsLittleEndian) {
Array.Reverse(ip);
}
int num = BitConverter.ToInt32(ip, 0);
và quay lại:
byte[] ip = BitConverter.GetBytes(num);
if (BitConverter.IsLittleEndian) {
Array.Reverse(ip);
}
string address = String.Join(".", ip.Select(n => n.ToString()));
uint
nếu bạn muốn 32 bit dữ liệu là một số không dấu, một int
có thể chứa cùng một thông tin. Nếu bạn muốn lưu trữ nó trong một cơ sở dữ liệu, một int
phù hợp hơn, bạn cần một bigint
để có thể lưu trữ nó ở dạng không dấu.
uint
bạn cũng không thể nhập nó vào thanh địa chỉ, trước tiên bạn phải chuyển nó thành dạng văn bản để làm điều đó. Chỉ vì sử dụng hình thức đơn giản nhất để chuyển một int
văn bản thành văn bản không tạo ra địa chỉ IP hoạt động không phải là một lý lẽ tốt để không sử dụng nó.
uint
, đó là đại diện văn bản của một uint
.
Tôi đã gặp một số vấn đề với các giải pháp được mô tả, khi đối mặt với Địa chỉ IP có giá trị rất lớn. Kết quả sẽ là byte [0] * 16777216 thingy sẽ tràn và trở thành một giá trị int âm. điều gì đã sửa nó cho tôi, là một thao tác đúc kiểu đơn giản.
public static long ConvertIPToLong(string ipAddress)
{
System.Net.IPAddress ip;
if (System.Net.IPAddress.TryParse(ipAddress, out ip))
{
byte[] bytes = ip.GetAddressBytes();
return
16777216L * bytes[0] +
65536 * bytes[1] +
256 * bytes[2] +
bytes[3]
;
}
else
return 0;
}
Mặt trái của chức năng Davy Landman
string IntToIp(int d)
{
int v1 = d & 0xff;
int v2 = (d >> 8) & 0xff;
int v3 = (d >> 16) & 0xff;
int v4 = (d >> 24);
return v4 + "." + v3 + "." + v2 + "." + v1;
}
Câu hỏi của tôi đã được đóng lại, tôi không biết tại sao. Câu trả lời được chấp nhận ở đây không giống với những gì tôi cần.
Điều này cung cấp cho tôi giá trị số nguyên chính xác cho một IP ..
public double IPAddressToNumber(string IPaddress)
{
int i;
string [] arrDec;
double num = 0;
if (IPaddress == "")
{
return 0;
}
else
{
arrDec = IPaddress.Split('.');
for(i = arrDec.Length - 1; i >= 0 ; i = i -1)
{
num += ((int.Parse(arrDec[i])%256) * Math.Pow(256 ,(3 - i )));
}
return num;
}
}
Với UInt32 ở định dạng little-endian thích hợp, đây là hai hàm chuyển đổi đơn giản:
public uint GetIpAsUInt32(string ipString)
{
IPAddress address = IPAddress.Parse(ipString);
byte[] ipBytes = address.GetAddressBytes();
Array.Reverse(ipBytes);
return BitConverter.ToUInt32(ipBytes, 0);
}
public string GetIpAsString(uint ipVal)
{
byte[] ipBytes = BitConverter.GetBytes(ipVal);
Array.Reverse(ipBytes);
return new IPAddress(ipBytes).ToString();
}
Tập hợp một số câu trả lời ở trên vào một phương thức mở rộng để xử lý Endianness của máy và xử lý các địa chỉ IPv4 đã được ánh xạ tới IPv6.
public static class IPAddressExtensions
{
/// <summary>
/// Converts IPv4 and IPv4 mapped to IPv6 addresses to an unsigned integer.
/// </summary>
/// <param name="address">The address to conver</param>
/// <returns>An unsigned integer that represents an IPv4 address.</returns>
public static uint ToUint(this IPAddress address)
{
if (address.AddressFamily == AddressFamily.InterNetwork || address.IsIPv4MappedToIPv6)
{
var bytes = address.GetAddressBytes();
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
return BitConverter.ToUInt32(bytes, 0);
}
throw new ArgumentOutOfRangeException("address", "Address must be IPv4 or IPv4 mapped to IPv6");
}
}
Bài kiểm tra đơn vị:
[TestClass]
public class IPAddressExtensionsTests
{
[TestMethod]
public void SimpleIp1()
{
var ip = IPAddress.Parse("0.0.0.15");
uint expected = GetExpected(0, 0, 0, 15);
Assert.AreEqual(expected, ip.ToUint());
}
[TestMethod]
public void SimpleIp2()
{
var ip = IPAddress.Parse("0.0.1.15");
uint expected = GetExpected(0, 0, 1, 15);
Assert.AreEqual(expected, ip.ToUint());
}
[TestMethod]
public void SimpleIpSix1()
{
var ip = IPAddress.Parse("0.0.0.15").MapToIPv6();
uint expected = GetExpected(0, 0, 0, 15);
Assert.AreEqual(expected, ip.ToUint());
}
[TestMethod]
public void SimpleIpSix2()
{
var ip = IPAddress.Parse("0.0.1.15").MapToIPv6();
uint expected = GetExpected(0, 0, 1, 15);
Assert.AreEqual(expected, ip.ToUint());
}
[TestMethod]
public void HighBits()
{
var ip = IPAddress.Parse("200.12.1.15").MapToIPv6();
uint expected = GetExpected(200, 12, 1, 15);
Assert.AreEqual(expected, ip.ToUint());
}
uint GetExpected(uint a, uint b, uint c, uint d)
{
return
(a * 256u * 256u * 256u) +
(b * 256u * 256u) +
(c * 256u) +
(d);
}
}
Nếu bạn quan tâm đến chức năng, không chỉ câu trả lời ở đây là cách nó được thực hiện:
int ipToInt(int first, int second,
int third, int fourth)
{
return Convert.ToInt32((first * Math.Pow(256, 3))
+ (second * Math.Pow(256, 2)) + (third * 256) + fourth);
}
với first
qua fourth
là các phân đoạn của địa chỉ IPv4.
public bool TryParseIPv4Address(string value, out uint result)
{
IPAddress ipAddress;
if (!IPAddress.TryParse(value, out ipAddress) ||
(ipAddress.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork))
{
result = 0;
return false;
}
result = BitConverter.ToUInt32(ipAddress.GetAddressBytes().Reverse().ToArray(), 0);
return true;
}
public static Int32 getLongIPAddress(string ipAddress)
{
return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0));
}
Ví dụ trên sẽ là cách tôi đi .. Chỉ có điều bạn có thể phải làm là chuyển đổi sang UInt32 cho mục đích hiển thị, hoặc mục đích chuỗi bao gồm sử dụng nó như một địa chỉ dài ở dạng chuỗi.
Đó là những gì cần thiết khi sử dụng hàm IPAddress.Parse (Chuỗi). Thở dài.
đây là một giải pháp mà tôi đã tìm ra hôm nay (đáng lẽ phải được đưa lên Google trước!):
private static string IpToDecimal2(string ipAddress)
{
// need a shift counter
int shift = 3;
// loop through the octets and compute the decimal version
var octets = ipAddress.Split('.').Select(p => long.Parse(p));
return octets.Aggregate(0L, (total, octet) => (total + (octet << (shift-- * 8)))).ToString();
}
tôi đang sử dụng LINQ, lambda và một số tiện ích mở rộng trên generic, vì vậy trong khi tạo ra kết quả tương tự, nó sử dụng một số tính năng ngôn ngữ mới và bạn có thể làm điều đó trong ba dòng mã.
tôi có lời giải thích trên blog của tôi nếu bạn quan tâm.
chúc mừng, -jc
Tôi nghĩ điều này là sai: "65536" ==> 0.0.255.255 "Nên là:" 65535 "==> 0.0.255.255" hoặc "65536" ==> 0.1.0.0 "
@Davy Ladman giải pháp của bạn với shift là đúng nhưng chỉ đối với ip bắt đầu bằng số nhỏ hơn hoặc bằng 99, bát phân đầu tiên của infact phải được đúc tối đa.
Dù sao chuyển đổi lại với kiểu dài là khá khó khăn vì lưu trữ 64 bit (không phải 32 cho Ip) và điền 4 byte bằng số 0
static uint ToInt(string addr)
{
return BitConverter.ToUInt32(IPAddress.Parse(addr).GetAddressBytes(), 0);
}
static string ToAddr(uint address)
{
return new IPAddress(address).ToString();
}
Thưởng thức!
Massimo
var address = IPAddress.Parse("10.0.11.174").GetAddressBytes();
long m_Address = ((address[3] << 24 | address[2] << 16 | address[1] << 8 | address[0]) & 0x0FFFFFFFF);
Hãy xem một số ví dụ phân tích cú pháp điên rồ trong Địa chỉ IP của .Net.Parse: ( MSDN )
"65536" ==> 0.0.255.255
"20.2" ==> 20.0.0.2
"20.65535" ==> 20.0.255.255
"128.1.2" ==> 128.1.0.2
int
s là little-endian trên hầu hết các hệ thống. Vì vậy, bạn phải đảo ngược các byte trước khi chuyển đổi. Xem câu trả lời của tôi để biết các chuyển đổi chính xác. Ngoài ra, ngay cả đối với IPv4, mộtint
không thể chứa các địa chỉ lớn hơn127.255.255.255
, ví dụ như địa chỉ quảng bá, vì vậy hãy sử dụng auint
.