Answers:
32位无符号整数是 IPv4地址。同时,IPAddress.Address
属性(虽然已弃用)是一个Int64,它返回IPv4地址的无符号32位值(注意,它是按网络字节顺序排列的,因此您需要对其进行交换)。
例如,我本地的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));
}
}
这是将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,因此,要获取正确的值,必须先反转字节,然后再在little-endian系统上进行转换。
另外,即使对于IPv4
,int
也无法容纳比127.255.255.255
广播地址大的地址(255.255.255.255)
,因此请使用uint
。
1.1.1.1
因为它的字节数组是回文的。尝试使用非回文疗法,例如127.0.0.1
或192.168.1.1
。
System.Net.IPAddress
才能使它正常工作。很棒!
2.1.1.2
也一样。
@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
因此您可以使用+将它们加起来,也可以将binairy或它们加在一起。结果为0x40E9BB63,即1089059683。(我认为以十六进制形式查看字节要容易得多)
因此,您可以将函数编写为:
int ipToInt(int first, int second,
int third, int fourth)
{
return (first << 24) | (second << 16) | (third << 8) | (fourth);
}
int
符号是有符号的,因此,如果将192移位24位,您将得到负整数,因此该代码将被破坏,因为高位字节首先具有高位。
试试这个:
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()
返回void,因此您不能调用ToArray()
它(供将来的读者使用)。相反,可以为反转的字节分配一个值,然后可以调用ToArray()。
由于没有人发布使用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()));
uint
如果要将32位数据作为无符号数字,int
则仅需要使用an ,它能够保存相同的信息。如果要将其存储在数据库int
中更合适,则需要a bigint
能够以未签名的形式存储它。
uint
您也无法在地址栏中输入的形式,首先必须将其转换为文本形式。仅仅因为使用最简单的形式将int
文本转换为文本不会产生有效的IP地址,对于不使用它不是一个很好的论据。
uint
,而是的文本表示形式uint
。
当面对价值非常高的IP地址时,我遇到了上述解决方案的一些问题。结果是,byte [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 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;
}
我的问题已经结束,我不知道为什么。这里接受的答案与我需要的答案不同。
这为我提供了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;
}
}
使用正确的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();
}
将以上几个答案组合到一个扩展方法中,该方法可以处理计算机的字节序并处理映射到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);
}
}
如果您对该功能感兴趣,不仅可以找到答案,还可以找到它的实现方式:
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;
}
这是我今天制定的解决方案(应该先用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和泛型的某些扩展,因此,尽管它产生相同的结果,但它使用了一些新的语言功能,并且可以用三行代码来实现。
如果您有兴趣,我会在我的博客上提供解释。
干杯,-jc
我认为这是错误的:“ 65536” ==> 0.0.255.255“应该是:” 65535“ ==> 0.0.255.255”或“ 65536” ==> 0.1.0.0“
@Davy Ladman您的移位解决方案是正确的,但仅对于以数字小于或等于99开头的ip,实际上第一个八位字节必须强制转换为long。
无论如何,用long类型转换回去是非常困难的,因为存储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();
}
请享用!
马西莫
var address = IPAddress.Parse("10.0.11.174").GetAddressBytes();
long m_Address = ((address[3] << 24 | address[2] << 16 | address[1] << 8 | address[0]) & 0x0FFFFFFFF);
int
在大多数系统上,s均为小端。因此,您必须在转换之前反转字节。请参阅我的答案以获得正确的转换。此外,即使对于IPv4,一个int
不能持有超过更大的地址127.255.255.255
,如广播地址,所以使用uint
。