如何将IPv4地址转换为C#中的整数?
我正在寻找一个function,将标准的IPv4地址转换为一个整数。 奖金积分可用于相反的function。
解决scheme应该在C#中。
// IPv4 int intAddress = BitConverter.ToInt32(IPAddress.Parse(address).GetAddressBytes(), 0); string ipAddress = new IPAddress(BitConverter.GetBytes(intAddress)).ToString();
编辑:正如在其他答案中指出的,当在一个小端机上运行这个片段时,它将按照标准定义的相反顺序发出字节。 但是,这个问题要求在整数和IP地址之间进行映射,而不是转换为标准整数格式。 要做到这一点,你必须考虑你正在运行的机器的sorting。
32位无符号整数是 IPv4地址。 同时, IPAddress.Address
属性虽然不赞成使用,但它是一个Int64,它返回IPv4地址的无符号32位值(捕获的是networking字节顺序,因此需要将其交换)。
例如,我的本地google.com位于64.233.187.99
。 这相当于:
64*2^24 + 233*2^16 + 187*2^8 + 99 = 1089059683
实际上, http:// 1089059683 /按照预期工作(至less在Windows中,使用IE,Firefox和Chrome进行testing;尽pipe如此,iPhone仍然无法正常工作)。
这里有一个testing程序来显示两个转换,包括networking/主机字节交换:
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)); } }
@Barry Kelly和@Andrew Hare,实际上,我不认为乘法是最明显的方法(非常正确)。
Int32“格式化”的IP地址可以被看作以下结构
[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.(在我看来,hex查看字节更容易)
所以你可以写这个函数为:
int ipToInt(int first, int second, int third, int fourth) { return (first << 24) | (second << 16) | (third << 8) | (fourth); }
从IPv4转换为正确的整数:
IPAddress address = IPAddress.Parse("255.255.255.255"); byte[] bytes = address.GetAddressBytes(); Array.Reverse(bytes); // flip big-endian(network order) to little-endian uint intAddress = BitConverter.ToUInt32(bytes, 0);
并转换回来:
byte[] bytes = BitConverter.GetBytes(4294967295); Array.Reverse(bytes); // flip little-endian to big-endian(network order) string ipAddress = new IPAddress(bytes).ToString();
说明:
IP地址是networking顺序(big-endian),而int
在Windows上是little-endian,所以要获得正确的值,必须在转换之前反转字节。
另外,即使对于IPv4
, int
也不能保存大于127.255.255.255
的地址,例如广播地址(255.255.255.255)
,所以使用uint
。
试试这个:
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(); }
由于没有人发布使用BitConverter
的代码,并实际检查字节顺序,这里是:
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()));
当遇到IP地址非常大的时候,我遇到了上述解决scheme的一些问题。 结果将是,字节[0] * 16777216 thingy将溢出,并成为一个负int值。 对我来说固定它是一个简单的types铸造操作。
public static long ConvertIPToLong(string ipAddress) { System.Net.IPAddress ip; if (System.Net.IPAddress.TryParse(ipAddress, out ip)) { byte[] bytes = ip.GetAddressBytes(); return (long) ( 16777216 * (long)bytes[0] + 65536 * (long)bytes[1] + 256 * (long)bytes[2] + (long)bytes[3] ) ; } else return 0; }
我的问题被closures了,我不知道为什么。 这里接受的答案与我所需要的不一样。
这给了我一个正确的整数值的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; } }
戴维·兰德曼的function正好相反
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; }
如果你对这个函数感兴趣的话,不仅仅是这个答案是这样做的:
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); }
first
到fourth
是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)); }
上面的例子将是我去的方式。唯一的事情你可能要做的是转换为UInt32用于显示的目的,或string的目的,包括使用它作为stringforms的长地址。
当使用IPAddress.Parse(String)函数时,这是需要的。 叹。
将上述几个答案组装成扩展方法,处理机器的字节序并处理映射到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"); } }
unit testing:
[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); } }
这是我今天制定的一个解决scheme(应该先Google!):
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和generics的一些扩展,所以虽然它产生相同的结果,它使用了一些新的语言function,你可以在三行代码。
如果你有兴趣,我在我的博客上有解释。
欢呼声,-JC
我认为这是错误的:“65536”==> 0.0.255.255“应该是:”65535“==> 0.0.255.255”或“65536”==> 0.1.0.0“
@Davy Ladman你的解决scheme是移植的,但是只能用于数字小于或等于99的ip,事实上,第一个字节必须长到很长。
无论如何用longtypes转换回来比较困难,因为存储64位(对于ip不是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(); }
请享用!
马西莫
使用适当的little-endian格式的UInt32,这里有两个简单的转换函数:
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(); }
假设你有一个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));
var ipAddress = "10.101.5.56"; var longAddress = long.Parse(string.Join("", ipAddress.Split('.').Select(x => x.PadLeft(3, '0')))); Console.WriteLine(longAddress);
输出:10101005056
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.Parse中的一些疯狂的parsing示例:( 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