C #에서 IPv4 주소를 정수로 변환하는 방법은 무엇입니까?


99

표준 IPv4 주소를 정수로 변환하는 함수를 찾고 있습니다. 반대로 수행 할 기능에 사용할 수있는 보너스 포인트.

솔루션은 C #이어야합니다.


15
경고 : IP 주소는 네트워크 순서 (big-endian)이고 s는 대부분의 시스템에서 little-endian 이기 때문에 수락 된 답변의 결과 정수는 잘못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에서 더 이상 사용되지 않습니다 .
— Erik Philips

@ErikPhilips IPv4 만 사용하는 것이 중요합니까?
— Ray

그것은 아키텍처 결정입니다. 장단점이 있으며 댓글은 특정 문제를 논의하기에 가장 좋은 위치가 아닙니다.
— Erik Philips

1
BitConverter.ToUInt32 (IPAddress.Parse (value) .GetAddressBytes (). Reverse (). ToArray ()를 사용하여 IPAddress.Address를 수정할 수 있습니다.
— Mhmd

43

다음은 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 주소는 네트워크 순서 (big-endian)이고 ints는 Windows에서 little-endian이므로 올바른 값을 얻으려면 little-endian 시스템에서 변환하기 전에 바이트를 반대로해야합니다.

또한 IPv4 이, int보다 큰 주소를 물을 수 없습니다 127.255.255.255브로드 캐스트 주소, 예를 (255.255.255.255), 그래서를 사용합니다 uint.


이것은 실제로 .NET을 사용하는 Windows에서 차이를 만들지 않는 것 같습니다. Mono에 대해서는 확실하지 않습니다. dotnetfiddle.net/cBIOj2
— Jesse

2
@Jesse 1.1.1.1는 바이트 배열이 회문이기 때문에 입력에 차이를 만들지 않습니다 . 비 회문 같은 사람과 시도 127.0.0.1나 192.168.1.1.
— Saeb Amini

나는 문제를 본다. 1.1.1.1, 와 같이 반복되는 숫자 2.2.2.2는 123.123.123.123항상 동일한 결과를 생성합니다. 후손에 대해서는 업데이트 된 바이올린을 참조하십시오. dotnetfiddle.net/aR6fhc
— Jesse

System.Net.IPAddress이 작업 을 수행 하기 위해 사용해야 했습니다. 잘 작동합니다!
— Shrout1

1
@Jesse는 반복되는 숫자가 아니라 모든 회문 IP 주소에 대한 것입니다. 그래서 2.1.1.2동일합니다.
— Saeb Amini

40

@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

그래서 당신은 +를 사용하여 그것들을 더할 수 있습니다. 결과는 1089059683 인 0x40E9BB63입니다. (내 의견으로는 16 진수로 보면 바이트를 보는 것이 훨씬 쉽습니다)

따라서 함수를 다음과 같이 작성할 수 있습니다.

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

1
나는 ip가 그러한 동작을 특별히 허용하는 방식으로 사양되었다고 믿습니다. 비트 시프트는 muls보다 대부분의 마이크로 프로세서에서 훨씬 효율적이며 추가합니다.
— Ape-inago 2009-06-14

1
2의 상수 거듭 제곱에 의한 @ Ape-inago 곱셈은 일반적으로 비트 시프트 fwiw로 최적화됩니다.
— Barry Kelly

대신 비트 이동, 당신은 사용할 수 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 ()를 호출 할 수 있습니다.
— Erik Philips

1
Reverse () 는 IEnumerable. 위의 코드는 완벽하게 괜찮습니다.
— 개미

3
이 방법은 특정 IP (예 : 140.117.0.0)에 대해 음수를 산출합니다
— lightxx

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
단위를 사용해야하지만 이것이 가장 정답입니다.
— RubberDuck 2015

1
@RubberDuck : uint32 비트 데이터를 부호없는 숫자로 원하는 경우 에만를 사용하면 됩니다 int.는 동일한 정보를 보유 할 수 있습니다. 데이터베이스에 저장하려는 경우 int더 적합 bigint하며 서명되지 않은 형식으로 저장할 수 있어야합니다.
— Guffa 2015

1
uint는 더 나은 표현 IMO입니다. 부호있는 int는 부호를 위해 약간 필요하므로 범위의 맨 위에있는 주소를 잃게됩니다. 예, 동일한 데이터를 보유 할 수 있지만, 주소 표시 줄에 입력하면 유효한 IP가 아닌 음수로 출력됩니다.
— RubberDuck 2015-11-29

@RubberDuck : uint주소 표시 줄에 입력 할 수없는 형식의 경우 먼저 텍스트 형식으로 변환해야합니다. int를 텍스트로 변환하는 가장 간단한 형식을 사용하는 것이 작동하는 IP 주소를 생성하지 않기 때문에 사용 하지 않는 것에 대한 좋은 주장이 아닙니다.
— Guffa 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;
}

나에게 최선의 해결책으로 보이지만 한 줄을 변경하면 byte [] bytes = ip.MapToIPv4 (). GetAddressBytes ();
— Walter Vehoeven

4

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

이것에 대해 더 설명해 주시겠습니까?
— 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 09.01.22

번호를 사용하려는 대상에 따라 다릅니다. IP를 찾기 위해> = 및 <= 쿼리를 수행하는 데 다른 변환을 사용할 수 없습니다.
— Coolcoder

2

적절한 리틀 엔디안 형식의 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();
}

2

위의 몇 가지 답변을 머신의 Endianness를 처리하고 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);
}

IPv4 주소의 세그먼트 를 first통해 fourth.


1
Math.Pow 대신 shift를 사용하면 더 명확 할 것 같습니다.
— Mehrdad Afshari

첫 번째가 127보다 크면 오버플로 예외가 발생합니다. Davy Landman의 대답이이를 수행하는 가장 좋은 방법입니다.
— mhenry1384

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, lambda 및 일부 확장을 제네릭에 사용하고 있으므로 동일한 결과를 생성하는 동안 새로운 언어 기능 중 일부를 사용하며 세 줄의 코드로 수행 할 수 있습니다.

관심이 있다면 내 블로그에 설명이 있습니다.

건배, -jc


0

잘못된 것 같습니다. "65536"==> 0.0.255.255 "다음과 같이해야합니다."65535 "==> 0.0.255.255"또는 "65536"==> 0.1.0.0 "


0

@Davy Ladman 시프트를 사용하는 솔루션은 corrent이지만 99보다 작거나 같은 숫자로 시작하는 ip에 대해서만 사실 첫 번째 옥 텍트는 long으로 캐스팅되어야합니다.

어쨌든 long 유형으로 다시 변환하는 것은 64 비트 (IP의 경우 32가 아님)를 저장하고 4 바이트를 0으로 채우기 때문에 매우 어렵습니다.

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

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

즐겨!

마시모


0

문자열 형식 (예 : 254.254.254.254)의 IP 주소가 있다고 가정합니다.

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 | 주소 [2] << 8 | 주소 [3]) & 0x0FFFFFFFF
— MiguelSlv

0

System.Net.IPAddress에는 Int64 데이터 형식도 허용하는 Address 속성 (System.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


이것은 실제로 대답이 아닙니다. 상위 답변 중 하나에 댓글을 달지 않으시겠습니까?
— DanM7
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.