Как преобразовать адрес IPv4 в целое число в C #? - PullRequest
94 голосов
/ 20 января 2009

Я ищу функцию, которая преобразует стандартный адрес IPv4 в целое число. Бонусные баллы доступны для функции, которая будет делать обратное.

Решение должно быть в C #.

Ответы [ 21 ]

135 голосов
/ 20 января 2009

32-разрядные целые числа без знака являются адресами IPv4. Между тем, свойство IPAddress.Address, хотя оно и устарело, является Int64, которое возвращает 32-разрядное значение без знака для адреса IPv4 (ловушка в том, что он находится в сетевом порядке байтов, поэтому вам необходимо поменять его местами).

Например, мой локальный сайт 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));
    }
}
38 голосов
/ 21 января 2009

@ Барри Келли и @ Эндрю Хэйр, вообще-то, я не думаю, что умножение - это самый очевидный способ сделать это (хотя и правильно).

IP-адрес в формате Int32 можно рассматривать как следующую структуру

[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);
}
29 голосов
/ 12 ноября 2012

Для преобразования из IPv4 в правильное целое число:

IPAddress address = IPAddress.Parse("255.255.255.254");
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(4294967294);
Array.Reverse(bytes); // flip little-endian to big-endian(network order)
string ipAddress = new IPAddress(bytes).ToString();

Пояснение:

IP-адреса в сетевом порядке (с прямым порядком байтов), в то время как int s имеют младший порядок в Windows, поэтому для получения правильного значения необходимо преобразовать байты перед преобразованием.

Кроме того, даже для IPv4 int не может содержать адреса больше 127.255.255.255, например широковещательный адрес (255.255.255.255), поэтому используйте uint.

12 голосов
/ 28 мая 2009

Попробуйте это:

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();
}
7 голосов
/ 01 ноября 2013

Поскольку никто не опубликовал код, который использует 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()));
6 голосов
/ 08 ноября 2010

У меня возникли некоторые проблемы с описанными решениями при обращении к 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 (long)
            (
            16777216 * (long)bytes[0] +
            65536 * (long)bytes[1] +
            256 * (long)bytes[2] +
            (long)bytes[3]
            )
            ;
    }
    else
        return 0;
}
4 голосов
/ 21 декабря 2013

Реверс функции Дэви Лэндмана

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;
}
3 голосов
/ 22 января 2009

Мой вопрос был закрыт, я понятия не имею, почему. Принятый ответ здесь не совпадает с тем, что мне нужно.

Это дает мне правильное целочисленное значение для 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;
    }
}
2 голосов
/ 31 мая 2015

Собрал несколько из приведенных выше ответов в метод расширения, который обрабатывает Endianness машины и обрабатывает адреса IPv4, которые были сопоставлены с IPv6.

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);
    }
}
1 голос
/ 17 апреля 2014
    public static Int32 getLongIPAddress(string ipAddress)
    {
        return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0));
    }

Приведенный выше пример был бы подходом. Единственное, что вам, возможно, придется сделать, - это преобразовать в UInt32 для отображения или строковых целей, включая использование его в качестве длинного адреса в строковой форме.

Что необходимо для использования функции IPAddress.Parse (String). Вздох.

...