web-dev-qa-db-fra.com

Comment convertir une adresse IPv4 en un entier en C #?

Je cherche une fonction qui convertira une adresse IPv4 standard en un entier. Points bonus disponibles pour une fonction qui fera le contraire.

La solution devrait être en C #.

89
GateKiller

Entiers non signés 32 bits are adresses IPv4. Pendant ce temps, la propriété IPAddress.Address, bien que déconseillée, est un Int64 qui renvoie la valeur non signée sur 32 bits de l'adresse IPv4 (le problème est qu'elle est dans l'ordre des octets du réseau, vous devez donc l'échanger).

Par exemple, mon site google.com local est à 64.233.187.99. Cela équivaut à:

64*2^24 + 233*2^16 + 187*2^8 + 99
= 1089059683

Et en effet,  http: // 1089059683/ fonctionne comme prévu (du moins sous Windows, testé avec IE, Firefox et Chrome; ne fonctionne pas sur iPhone cependant).

Voici un programme de test pour afficher les deux conversions, y compris la permutation d'octets réseau/hôte:

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));
    }
}
130
Barry Kelly

@Barry Kelly et @Andrew Hare, en fait, je ne pense pas que la multiplication soit le moyen le plus clair de procéder (tout à fait correct).

Une adresse IP "formatée" Int32 peut être considérée comme la structure suivante

[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

Donc, pour convertir l'adresse IP 64.233.187.99, vous pouvez faire:

(64  = 0x40) << 24 == 0x40000000
(233 = 0xE9) << 16 == 0x00E90000
(187 = 0xBB) << 8  == 0x0000BB00
(99  = 0x63)       == 0x00000063
                      ---------- =|
                      0x40E9BB63

afin que vous puissiez les additionner en utilisant + ou vous pouvez binairy ou les deux ensemble. Résultat dans 0x40E9BB63 qui est 1089059683. (À mon avis, regarder dans l'hex est beaucoup plus facile de voir les octets)

Pour que vous puissiez écrire la fonction comme:

int ipToInt(int first, int second, 
    int third, int fourth)
{
    return (first << 24) | (second << 16) | (third << 8) | (fourth);
}
37
Davy Landman

Pour convertir d’IPv4 en entier correct:

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

Et pour reconvertir:

byte[] bytes = BitConverter.GetBytes(4294967294);
Array.Reverse(bytes); // flip little-endian to big-endian(network order)
string ipAddress = new IPAddress(bytes).ToString();

Explication:

Les adresses IP sont dans l'ordre du réseau (big-endian), alors que ints est un peu-endian sous Windows. Pour obtenir une valeur correcte, vous devez inverser les octets avant de convertir.

De même, même pour IPv4, une int ne peut pas contenir d’adresses plus grandes que 127.255.255.255, par exemple. l'adresse de diffusion (255.255.255.255), utilisez donc une uint.

29
Saeb Amini

Essayez ceux-ci:

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

Comme personne n’a posté le code qui utilise BitConverter et vérifie réellement l’endianisme, voici:

byte[] ip = address.Split('.').Select(s => Byte.Parse(s)).ToArray();
if (BitConverter.IsLittleEndian) {
  Array.Reverse(ip);
}
int num = BitConverter.ToInt32(ip, 0);

et retour:

byte[] ip = BitConverter.GetBytes(num);
if (BitConverter.IsLittleEndian) {
  Array.Reverse(ip);
}
string address = String.Join(".", ip.Select(n => n.ToString()));
7
Guffa

J'ai rencontré quelques problèmes avec les solutions décrites, en faisant face à des adresses IP avec une très grande valeur . Le résultat serait que l'octet [0] * 16777216 chose déborderait et deviendrait une valeur int négative . corrigé pour moi, c’est une opération de transtypage simple.

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;
}
6
Qiong Wu

Ma question était fermée, je ne sais pas pourquoi. La réponse acceptée ici n’est pas la même chose que ce dont j’ai besoin. 

Cela me donne la valeur entière correcte pour un 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;
    }
}
3
Coolcoder

Assemblé plusieurs des réponses ci-dessus dans une méthode d'extension qui gère l'endianité de la machine et les adresses IPv4 mappées sur 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");
    }
}

Tests unitaires:

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

Le revers de la fonction de 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;
}
2
Aris Schizas
    public static Int32 getLongIPAddress(string ipAddress)
    {
        return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0));
    }

L’exemple ci-dessus serait ma façon de faire. La seule chose à faire est de convertir un fichier UInt32 à des fins d’affichage ou de chaîne, y compris en l’utilisant comme adresse longue sous forme de chaîne.

Quel est ce qui est nécessaire lorsque vous utilisez la fonction IPAddress.Parse (String). Soupir.

1
Gerard ONeill

Avec le UInt32 au format little-endian approprié, voici deux fonctions de conversion simples:

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

Si la fonction ne vous intéresse pas, la réponse est la suivante:

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

avec first à fourth étant les segments de l'adresse IPv4.

1
Andrew Hare

En supposant que vous ayez une adresse IP au format chaîne (par exemple, 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));
0
Andrew

Je pense que c'est faux: "65536" ==> 0.0.255.255 " Devrait être:" 65535 "==> 0.0.255.255" ou "65536" ==> 0.1.0.0 "

0
Marian
var ipAddress = "10.101.5.56";

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

Console.WriteLine(longAddress);

Sortie: 10101005056

0
xagyg

@ David Ladman votre solution avec shift sont correctes, mais uniquement pour ip commençant avec un nombre inférieur ou égal à 99, en fait, le premier octet doit être lancé trop longtemps.

Quoi qu'il en soit, reconvertir avec un type long est assez difficile car stocker 64 bits (pas 32 pour Ip) et remplir 4 octets avec des zéros

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

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

Prendre plaisir!

Massimo

0
Massimo

J'ai remarqué que System.Net.IPAddress possède une propriété Address (System.Int64) et un constructeur acceptant également le type de données Int64. Vous pouvez donc l'utiliser pour convertir l'adresse IP en/à partir du format numérique (bien que ce ne soit pas Int32, mais Int64).

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

voici une solution que j'ai mise au point aujourd'hui (j'aurais dû googler en premier!):

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

j'utilise LINQ, lambda et certaines des extensions sur les génériques. Par conséquent, même s'il produit le même résultat, il utilise certaines des nouvelles fonctionnalités du langage et vous pouvez le faire en trois lignes de code.

j'ai l'explication sur mon blog si cela vous intéresse.

acclamations, - jc

0
James Chambers