Как преобразовать адрес IPv4 в целое число в С#?

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

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

Ответ 1

// IPv4
int intAddress = BitConverter.ToInt32(IPAddress.Parse(address).GetAddressBytes(), 0);
string ipAddress = new IPAddress(BitConverter.GetBytes(intAddress)).ToString();

РЕДАКТИРОВАТЬ: Как отмечено в других ответах, при запуске этого фрагмента на маленькой конечной машине он выдаст байты в обратном порядке, как определено стандартом. Тем не менее, вопрос требует сопоставления между целым числом и IP-адресом, а не преобразованием в стандартный целочисленный формат. Для этого вам необходимо рассмотреть конечную версию машины, на которой вы работаете.

Ответ 2

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

Ответ 3

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

Ответ 4

Вот пара методов для преобразования из 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 имеют младший порядок байтов, поэтому для получения правильного значения вы должны обратить байты в обратном порядке, прежде чем конвертировать в систему с прямым порядком байтов.

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

Ответ 5

Попробуйте следующее:

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

Ответ 6

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

Ответ 7

Я столкнулся с некоторыми проблемами с описанными решениями, столкнувшись с IP-адресами с очень большим значением. Результатом было бы то, что байт [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;
}

Ответ 8

Обратная функция Дэви Ландмана

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

Ответ 9

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

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

Ответ 10

Соберил несколько из приведенных выше ответов в метод расширения, который обрабатывает 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);
    }
}

Ответ 11

Если вас заинтересовала функция, не только ответ здесь, как это делается:

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.

Ответ 12

С UInt32 в правильном формате little-endian, вот две простые функции преобразования:

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

Ответ 13

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

Ответ 14

    public static Int32 getLongIPAddress(string ipAddress)
    {
        return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0));
    }

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

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

Ответ 15

вот решение, которое я разработал сегодня (должен был сначала googled!):

    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, поэтому, пока он производит тот же результат, он использует некоторые новые функции языка, и вы можете сделать это в трех строках кода.

У меня есть объяснение на моем блоге, если вы заинтересованы.

веселит, -jc

Ответ 16

Я думаю, что это неправильно: "65536" == > 0.0.255.255 "Должно быть:" 65535 "== > 0.0.255.255" или "65536" == > 0.1.0.0"

Ответ 17

@Davy Ladman ваше решение со сдвигом - это corrent, но только для ip, начинающегося с номера меньше или равного 99, infact first octect должен быть отброшен до конца.

В любом случае конвертировать назад с длинным типом довольно сложно, потому что хранилище 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();
}

Наслаждайтесь!

Массимо

Ответ 18

Предполагая, что у вас есть 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));

Ответ 19

var ipAddress = "10.101.5.56";

var longAddress = long.Parse(string.Join("", ipAddress.Split('.').Select(x => x.PadLeft(3, '0'))));

Console.WriteLine(longAddress);

Выход: 10101005056

Ответ 20

var address = IPAddress.Parse("10.0.11.174").GetAddressBytes();
long m_Address = ((address[3] << 24 | address[2] << 16 | address[1] << 8 | address[0]) & 0x0FFFFFFFF);

Ответ 21

Я заметил, что System.Net.IPAddress имеет свойство Address (System.Int64) и конструктор, которые также принимают тип данных Int64. Таким образом, вы можете использовать это для преобразования IP-адреса в/из числового (хотя не Int32, но Int64) формата.

Ответ 22

Взгляните на некоторые из безумных примеров синтаксического анализа в .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