我正在寻找一个将标准IPv4地址转换为整数的函数.可用于相反功能的奖励积分.
解决方案应该在C#中.
32位无符号整数是 IPv4地址.同时,该IPAddress.Address
属性虽然已被弃用,但它是一个Int64,它返回IPv4地址的无符号32位值(catch是,它是以网络字节顺序,所以你需要交换它).
例如,我的本地google.com就在64.233.187.99
.这相当于:
64*2^24 + 233*2^16 + 187*2^8 + 99 = 1089059683
事实上, http:// 1089059683 /按预期工作(至少在Windows中,使用IE,Firefox和Chrome进行测试;但在iPhone上不起作用).
这是一个显示两种转换的测试程序,包括网络/主机字节交换:
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.(在我看来,以十六进制查看更容易看到字节)
所以你可以把函数写成:
int ipToInt(int first, int second, int third, int fourth) { return (first << 24) | (second << 16) | (third << 8) | (fourth); }
要从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),而int
s在Windows上是little-endian,因此要获得正确的值,必须在转换之前反转字节.
而且,即使是IPv4
,int
也不能保持大于127.255.255.255
例如广播地址的地址(255.255.255.255)
,所以使用a 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地址时,我遇到了所描述的解决方案的一些问题.结果是,byte [0]*16777216 thingy会溢出并成为负int值.对我来说固定它的是一种简单的铸造操作.
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; }