簡體   English   中英

如何在 C# 中將 IPv4 地址轉換為整數?

[英]How to convert an IPv4 address into a integer in C#?

我正在尋找將標准 IPv4 地址轉換為整數的函數。 獎勵積分可用於相反的功能。

解決方案應該在 C# 中。

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 地址采用網絡順序(大端),而int在 Windows 上是小端,因此要獲得正確的值,您必須在小端系統上轉換之前反轉字節。

此外,即使對於IPv4int也不能保存大於127.255.255.255的地址,例如廣播地址(255.255.255.255) ,因此請使用uint

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

試試這個:

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

當面對具有非常大值的 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
            16777216L * bytes[0] +
            65536 * bytes[1] +
            256 * bytes[2] +
            bytes[3]
            ;
    }
    else
        return 0;
}

由於沒有人發布使用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()));

戴維蘭德曼函數的反轉

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

使用適當的小端格式的 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();
}
    public static Int32 getLongIPAddress(string ipAddress)
    {
        return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0));
    }

上面的例子就是我要走的路.. 唯一你可能需要做的是轉換為 UInt32 用於顯示目的,或字符串目的,包括將其用作字符串形式的長地址。

這是使用 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");
    }
}

單元測試:

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

如果您對該功能感興趣,那么這里的答案不僅僅是它是如何完成的:

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 地址的段。

將 IP 編號的所有部分乘以 256 的冪(256x256x256、256x256、256 和 1。例如:

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

假設您有一個字符串格式的 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);

@Davy Ladman 您的 shift 解決方案是正確的,但僅適用於以小於或等於 99 的數字開頭的 ip,實際上必須將第一個八位字節轉換為 long。

無論如何轉換回 long 類型是相當困難的,因為存儲 64 位(不是 32 位 Ip)並用零填充 4 個字節

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

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

享受!

馬西莫

我注意到 System.Net.IPAddress 有 Address 屬性(System.Int64)和構造函數,它們也接受 Int64 數據類型。 因此,您可以使用它來將 IP 地址轉換為數字(雖然不是 Int32,而是 Int64)格式。

這是我今天制定的解決方案(應該先用谷歌搜索!):

    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"

看看 .Net 的 IPAddress.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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM