如何在 C # 中将 IPv4地址转换为整数?

我正在寻找一个功能,将转换成一个标准的 IPv4地址整数。可用于做相反事情的函数的加分。

Solution should be in C#.

147155 次浏览

32位无符号整数 IPv4地址。同时,IPAddress.Address属性虽然不被推荐,但是它是一个 Int64,返回 IPv4地址的无符号32位值(捕捉到的是,它是按网络字节顺序排列的,因此需要交换它)。

例如,我本地的 google.com 位于 64.233.187.99,这相当于:

64*2^24 + 233*2^16 + 187*2^8 + 99
= 1089059683

And indeed, 译自: 美国《 http://1089059683/》杂志网站(http://1089059683/rel = “ norefrer”) works as expected (at least in Windows, tested with IE, Firefox and Chrome; doesn't work on iPhone though).

这里有一个测试程序来显示这两种转换,包括网络/主机字节交换:

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));
}
}

如果你对这个函数感兴趣,这里的答案不仅仅是它是如何完成的:

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);
}

firstfourth是 IPv4地址的片段。

@ Barry Kelly 和@Andrew Hare,实际上,我不认为乘法是最清楚的方法(完全正确)。

An Int32 "formatted" IP address can be seen as the following structure

[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

因此,要转换 ip 地址64.233.187.99,你可以这样做:

(64  = 0x40) << 24 == 0x40000000
(233 = 0xE9) << 16 == 0x00E90000
(187 = 0xBB) << 8  == 0x0000BB00
(99  = 0x63)       == 0x00000063
---------- =|
0x40E9BB63

所以你可以用 + 把它们加起来,或者你可以用二进制或者把它们加起来。结果为0x40E9BB63,即1089059683。(在我看来,用十六进制查看字节要容易得多)

所以你可以把函数写成:

int ipToInt(int first, int second,
int third, int fourth)
{
return (first << 24) | (second << 16) | (third << 8) | (fourth);
}

看看.Net 的 IPAddress 中一些疯狂的解析示例: (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 < bR >

我的问题结束了,我不知道为什么。这里接受的答案与我需要的不一样。

这给了我一个正确的整数值的 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;
}
}

这是我今天想出来的一个解决方案(我应该先谷歌一下的!) :

    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();
}

我在泛型上使用 LINQ,lambda 和一些扩展,所以当它产生相同的结果时,它使用了一些新的语言特性,你可以在三行代码中完成。

如果你感兴趣的话,我在我的博客上有解释。

cheers, JC

试试这个:

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();
}

我认为这是错误的: “65536”= = > 0.0.255.255 应该是: “65535”= = > 0.0.255.255”或“65536”= = > 0.1.0.0

我遇到了一些问题与所描述的解决方案,当面临的 IP 地址与一个非常大的价值。 结果是,字节[0] * 16777216会溢出并变成负的 int 值。 为我固定的,是一个简单的类型铸造操作。

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;
}

@ Davy Ladman 你的 shift 解法是正确的,但只适用于从数字小于或等于99开始的 ip,事实上第一个八位数必须被加长。

无论如何,转换回长类型是相当困难的,因为存储64位(而不是32叶)和填充4字节与零

static uint ToInt(string addr)
{
return BitConverter.ToUInt32(IPAddress.Parse(addr).GetAddressBytes(), 0);
}


static string ToAddr(uint address)
{
return new IPAddress(address).ToString();
}

好好享受吧!

Massimo

下面是一对将 IPv4转换为 正确整数并返回的方法:

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();
}

例子

ConvertFromIpAddressToInteger("255.255.255.254"); // 4294967294
ConvertFromIntegerToIpAddress(4294967294); // 255.255.255.254

解释

IP 地址按网络顺序排列(big-endian) ,而在 Windows 上 int是 little-endian,因此要获得正确的值,必须在在 little-endian 系统上进行转换之前反转字节。

此外,即使对于 IPv4int也不能保存比 127.255.255.255大的地址,例如广播地址 (255.255.255.255),所以使用 uint

With the UInt32 in the proper little-endian format, here are two simple conversion functions:

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();
}
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;
}

As noone posted the code that uses BitConverter and actually checks the endianness, here goes:

byte[] ip = address.Split('.').Select(s => Byte.Parse(s)).ToArray();
if (BitConverter.IsLittleEndian) {
Array.Reverse(ip);
}
int num = BitConverter.ToInt32(ip, 0);

然后回来:

byte[] ip = BitConverter.GetBytes(num);
if (BitConverter.IsLittleEndian) {
Array.Reverse(ip);
}
string address = String.Join(".", ip.Select(n => n.ToString()));

与 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;
}
    public static Int32 getLongIPAddress(string ipAddress)
{
return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0));
}

上面的例子就是我要走的路。.您可能需要做的唯一一件事情是为了显示目的转换为 UInt32,或者为了字符串目的,包括以字符串形式使用它作为长地址。

这是使用 IPAddress. Parse (String)函数时所需要的。

假设您有一个字符串格式的 IP 地址(例如254.254.254.254)

string[] vals = inVal.Split('.');
uint output = 0;
for (byte i = 0; i < vals.Length; i++) output += (uint)(byte.Parse(vals[i]) << 8 * (vals.GetUpperBound(0) - i));

将上述几个答案组合成一个扩展方法,该方法处理计算机的 Endianness 并处理映射到 IPv6的 IPv4地址。

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");
}
}

单元测试:

[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);
}
}
var address = IPAddress.Parse("10.0.11.174").GetAddressBytes();
long m_Address = ((address[3] << 24 | address[2] << 16 | address[1] << 8 | address[0]) & 0x0FFFFFFFF);

我注意到系统。Net.IPAddress 具有 Address 属性(System。和构造函数,它们也接受 Int64数据类型。因此,您可以使用它将 IP 地址转换为/从数字格式(尽管不是 Int32,而是 Int64)。

将 IP 号的所有部分乘以256的幂(256x256x256,256x256,256和1) ,例如:

IPv4地址: 127.0.0.1 32位数字: = (127x256 ^ 3) + (0x256 ^ 2) + (0x256 ^ 1) + 1 = 2130706433

我用这个:

public static uint IpToUInt32(string ip)
{
if (!IPAddress.TryParse(ip, out IPAddress address)) return 0;
return BitConverter.ToUInt32(address.GetAddressBytes(), 0);
}


public static string UInt32ToIp(uint address)
{
return new IPAddress(address).ToString();
}