C#でIPv4アドレスを整数に変換する方法は?


99

標準のIPv4アドレスを整数に変換する関数を探しています。反対のことをする関数に利用できるボーナスポイント。

ソリューションはC#である必要があります。


15
警告:IPアドレスはネットワーク順(ビッグエンディアン)ですが、sはほとんどのシステムでリトルエンディアンであるため、受け入れられた回答から得られる整数は間違っていintます。したがって、変換する前にバイトを逆にする必要があります。正しい変換については私の答えを参照しください。また、でもIPv4のために、intより大きなアドレスを保持することができない127.255.255.255例えばので使用し、ブロードキャストアドレスをuint
Saeb Amini、

回答:


137

32ビットの符号なし整数 IPv4アドレスです。一方、このIPAddress.Addressプロパティは非推奨ですが、IPv4アドレスの符号なし32ビット値を返すInt64です(キャッチは、ネットワークバイト順であるため、入れ替える必要があります)。

たとえば、私のローカル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));
    }
}

2
Ubuntu Linux 10.04のOpera 11で確認済み:intをおなじみのwxyz形式に変換し、それが機能します。
Piskvorが

6
IPAddress.Addressは、.Net 4.0で廃止されました。
エリックフィリップス

@ErikPhilips IPv4のみを使用している場合に問題はありますか?
レイ

それはアーキテクチャ上の決定です。それには長所と短所があり、コメントはその特定の問題を議論するのに最適な場所ではありません。
エリックフィリップス

1
BitConverter.ToUInt32(IPAddress.Parse(value).GetAddressBytes()。Reverse()。ToArray()を使用してIPAddress.Addressが廃止されていることを修正できます
Mhmd

43

次に、IPv4から正しい整数に変換して戻すための 2つの方法を示します。

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アドレスはネットワーク順(ビッグエンディアン)ですが、intsはWindowsではリトルエンディアンなので、正しい値を取得するには、リトルエンディアンシステムで変換する前にバイトを逆にする必要があります。

また、さえのためにIPv4intより大きなアドレスを保持することはできません127.255.255.255ブロードキャストアドレス、例えば(255.255.255.255)、その使用uint


これは実際にはWindowsで.NETを使用して変化をもたらすようには見えません-Monoについては不明です。dotnetfiddle.net/cBIOj2
Jesse

2
@Jesse 1.1.1.1そのバイト配列は回文的であるため、たまたまあなたの入力に違いはありません。127.0.0.1またはのような非回文的なもので試してください192.168.1.1
Saeb Amini、2018

問題が発生しました。1.1.1.1、などの繰り返し数2.2.2.2123.123.123.123常に同じ結果になります。後世については、更新されたフィドルを参照してください:dotnetfiddle.net/aR6fhc
ジェシー

System.Net.IPAddressこれを機能させるために使用しなければならなかったことに注意したい。よく働く!
Shrout1

1
@Jesseは、繰り返し番号だけでなく、すべての回文 IPアドレスを対象としています。だから2.1.1.2同じだろう。
Saeb Amini、

40

@バリー・ケリーと@アンドリュー・ヘア、実際には、乗算はこれを行うための最も明確な方法だとは思いません(完全に正しい)。

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またはそれらを一緒にしたりできます。その結果、1089059683である0x40E9BB63になります(16進数で見ると、バイトが見やすくなります)。

したがって、関数は次のように書くことができます。

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

1
IPはそのような動作を具体的に許可するようにそのように指定されていたと思います...ほとんどのマイクロプロセッサでは、mulsやaddよりもビットシフトの方がはるかに効率的です。
Ape-in​​ago

1
2の定数乗による@ Ape-in​​ago乗算は、通常、ビットシフトに最適化されます(fwiw)。
バリーケリー

ビットシフトの代わりに、LayoutKind.ExplicitおよびFieldOffsetを使用して、バイトが格納される順序を逆にすることができます。もちろん、これはリトルエンディアンアーキテクチャでのみ機能します。githubの例
RubberDuck、2015年

2
int署名されていることを指摘する必要があるので、192を24ビットシフトすると負の整数が得られるので、最初に高ビットを持つ高オクテットでこのコードは壊れます。
Mateusz

12

これを試してください:

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()を呼び出すことができます。
エリックフィリップス

1
Reverse()はの拡張メソッドですIEnumerable。上記のコードは完全に大丈夫です。
Ant

3
この方法では、特定のIP(140.117.0.0など)に対して負の数が生成されます
lightxx 2015年

7

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

2
uintを使用する必要がありますが、これがここでの最も正しい答えです。
RubberDuck、2015年

1
@RubberDuck:uint32ビットのデータを符号なしの数値として使用したい場合にのみ使用する必要がありintます。同じ情報を保持できます。データベースに保存したい場合は、署名なしの形式で保存できるようにするint必要がありますbigint
Guffa 2015年

1
uintはIMOをより適切に表現します。符号付きintは符号に少し必要なので、範囲の最上部のアドレスを失います。はい、同じデータを保持できますが、アドレスバーに入力すると有効なIPではない負の数として出力されます。
RubberDuck、2015年

@RubberDuck:uintアドレスバーにも入力できない形式では、まずテキスト形式に変換する必要があります。intをテキストに変換する最も単純な形式を使用しても機能するIPアドレスが生成されないからといって、IPアドレスを使用しないことは適切ではありません。
グッファ2015年

@RubberDuck:これは、uintではなく、のテキスト表現ですuint
Guffa 2015年

7

非常に大きな値を持つ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;
}

最善の解決策として私に見えますが、1行を変更するため、byte [] bytes = ip.MapToIPv4()。GetAddressBytes();を実行します。
Walter Vehoeven

4

デイビーランドマンの機能の逆

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

これについてもっと説明してもらえますか?
Developerium

3

質問は締め切られました。理由はわかりません。ここで受け入れられた答えは、私が必要としているものと同じではありません。

これにより、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;
    }
}

あなたが両方の方法で変換を行うことができる限り、一貫している限り出力番号が正しい必要がある理由はわかりません。
GateKiller 2009年

番号を何に使用するかによって異なります。あなたが行うため、他の変換を使用するカント> =と<=クエリIP ..見つけるために
Coolcoder

2

適切なリトルエンディアン形式のUInt32を使用した、2つの簡単な変換関数を次に示します。

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

2

上記の回答のいくつかを、マシンのエンディアンを処理し、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);
    }
}

1

あなたが関数に興味を持っていたなら、ここでの答えだけではなく、それがどのように行われるかです:

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を介してfourthIPv4アドレスのセグメントです。


1
Math.Powの代わりにshiftを使用した方がより明確になると思います。
Mehrdad Afshari、

最初は> 127の場合、これはオーバーフロー例外をスローします。これを行うには、Davy Landmanの答えが最良の方法です。
mhenry1384 2012

int32は署名されているため、最初のオクテットに対して127より大きい負の値を返します
Mateusz

1
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
    public static Int32 getLongIPAddress(string ipAddress)
    {
        return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0));
    }

上記の例は私が行く方法です...あなたがしなければならないかもしれない唯一のことは、表示目的、または文字列形式の長いアドレスとして使用することを含む文字列目的のためにUInt32に変換することです。

これは、IPAddress.Parse(String)関数を使用するときに必要なものです。はぁ。


0

ここに私が今日解決した解決策があります(最初にググったほうがいいです!):

    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、ラムダ、ジェネリックのいくつかの拡張機能を使用しているため、同じ結果が得られますが、新しい言語機能のいくつかが使用され、3行のコードで実行できます。

興味があればブログに説明があります。

乾杯、-jc


0

これは間違っていると思います: "65536" ==> 0.0.255.255 "でなければなりません:" 65535 "==> 0.0.255.255"または "65536" ==> 0.1.0.0 "


0

@Davy Ladmanシフトを使用したソリューションは正しいですが、99以下の番号で始まるIPの場合のみ、無傷の最初のオクテットを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();
}

楽しい!

マッシモ


0

文字列形式の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));

0
var ipAddress = "10.101.5.56";

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

Console.WriteLine(longAddress);

出力:10101005056


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

GetAddressBytesメソッドは、マシンがエンディアンであるかエンディアンであるかに応じて、バイトを逆の順序で返す場合があるため、一部のマシンでは正しいステートメントになる場合があります。long m_Address =(address [0] << 24 | address [1] << 16 | address [2] << 8 | address [3])&0x0FFFFFFFF
MiguelSlv

0

System.Net.IPAddressにはAddressプロパティ(System.Int64)とコンストラクターがあり、Int64データ型も受け入れることに気付きました。したがって、これを使用して、IPアドレスを数値(/ Int32ではなくInt64)形式に変換できます。


-1

.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


これは本当に答えではありません。よくある回答の1つにコメントしてください。
DanM7 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.