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.1192.168.1.1.
Saeb Amini

나는 문제를 본다. 1.1.1.1, 와 같이 반복되는 숫자 2.2.2.2123.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.ExplicitFieldOffset바이트가 저장되는 순서를 반대로. 물론 이는 리틀 엔디안 아키텍처에서만 작동합니다. 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.