AVISO : os inteiros resultantes da resposta aceita estarão errados , porque os endereços IP estão na ordem da rede (big-endian), enquanto ints são little-endian na maioria dos sistemas. Portanto, você deve inverter os bytes antes de converter. Veja minha resposta para conversões corretas. Além disso, mesmo para IPv4, um intnão pode conter endereços maiores que 127.255.255.255, por exemplo , o endereço de broadcast, então use a uint.
Saeb Amini
Respostas:
137
Inteiros não assinados de 32 bits são endereços IPv4. Enquanto isso, oIPAddress.Address propriedade, embora obsoleta, é um Int64 que retorna o valor de 32 bits não assinado do endereço IPv4 (o problema é que está na ordem de bytes da rede, então você precisa trocá-lo).
Por exemplo, meu google.com local é em 64.233.187.99. Isso é equivalente a:
64*2^24+233*2^16+187*2^8+99=1089059683
E realmente, http: // 1089059683 / funciona como esperado (pelo menos no Windows, testado com IE, Firefox e Chrome; embora não funcione no iPhone).
Este é um programa de teste para mostrar ambas as conversões, incluindo a troca de bytes de rede / host:
using System;
using System.Net;classApp{staticlongToInt(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);}staticstringToAddr(long address){returnIPAddress.Parse(address.ToString()).ToString();// This also works:// return new IPAddress((uint) IPAddress.HostToNetworkOrder(// (int) address)).ToString();}staticvoidMain(){Console.WriteLine(ToInt("64.233.187.99"));Console.WriteLine(ToAddr(1089059683));}}
Os endereços IP estão na ordem da rede (big-endian), enquanto ints são little-endian no Windows, portanto, para obter um valor correto, você deve reverter os bytes antes de converter em um sistema little-endian.
Além disso, mesmo para IPv4an intnão pode conter endereços maiores do que 127.255.255.255, por exemplo, o endereço de broadcast (255.255.255.255), então use a uint.
Na verdade, isso não parece fazer diferença no Windows usando .NET - não tenho certeza sobre o Mono. Consulte dotnetfiddle.net/cBIOj2
Jesse
2
@Jesse acontece de não fazer diferença para sua entrada de 1.1.1.1porque seu array de bytes é palíndromo. Experimente com os não palíndrômicos como 127.0.0.1ou 192.168.1.1.
Saeb Amini
Eu vejo o problema. Números repetidos, tais como 1.1.1.1, 2.2.2.2, 123.123.123.123sempre produzir o mesmo resultado. Para a posteridade, veja o violino atualizado: dotnetfiddle.net/aR6fhc
Jesse
Gosto de observar que eu tive que usar System.Net.IPAddresspara fazer isso funcionar. Funciona bem!
Shrout1
1
@Jesse isso não seria apenas para repetir números, mas para todos os endereços IP palíndromos . Então 2.1.1.2seria o mesmo.
Saeb Amini
40
@Barry Kelly e @Andrew Hare, na verdade, não acho que a multiplicação seja a maneira mais clara de fazer isso (totalmente correto).
Um endereço IP "formatado" Int32 pode ser visto como a seguinte estrutura
[StructLayout(LayoutKind.Sequential,Pack=1)]structIPv4Address{publicByte A;publicByte B;publicByte C;publicByte D;}// to actually cast it from or to an int32 I think you // need to reverse the fields due to little endian
Portanto, para converter o endereço IP 64.233.187.99, você pode fazer:
então você pode somar usando + ou você pode binairy ou eles juntos. Resultando em 0x40E9BB63 que é 1089059683. (Na minha opinião, olhando em hexadecimal é muito mais fácil ver os bytes)
Então você pode escrever a função como:
int ipToInt(int first,int second,int third,int fourth){return(first <<24)|(second <<16)|(third <<8)|(fourth);}
Eu acredito que os ip's foram especificados dessa forma para permitir especificamente tal comportamento ... bit shifts são muito mais eficientes na maioria dos microprocessadores do que muls e add.
Ape-inago
1
@ As multiplicações ape-inago por potências constantes de dois são normalmente otimizadas em trocas de bits, fwiw.
Barry Kelly
Em vez de deslocamento de bits, você pode usar LayoutKind.Explicite FieldOffsetpara inverter a ordem em que os bytes são armazenados. Claro, isso só funciona para a arquitetura little endian. Exemplo no github .
RubberDuck
2
Tem que apontar que inté assinado então se você deslocar 192 por 24 bits você obterá um inteiro negativo então este código é quebrado para octeto alto tendo bit alto em primeiro lugar.
Reverse()retorna void, então você não pode chamá ToArray()-lo (para leitores futuros). Em vez disso, atribua um valor aos bytes invertidos, então você pode chamar ToArray ().
Erik Philips
1
Reverse () é o método de extensão de IEnumerable. O código acima está perfeitamente ok.
Formiga
3
Este método produz números negativos para determinados IPs (por exemplo, 140.117.0.0)
lightxx
7
Como ninguém postou o código que usa BitConvertere realmente verifica o endianness, aqui vai:
byte[] ip = address.Split('.').Select(s =>Byte.Parse(s)).ToArray();if(BitConverter.IsLittleEndian){Array.Reverse(ip);}int num =BitConverter.ToInt32(ip,0);
e volta:
byte[] ip =BitConverter.GetBytes(num);if(BitConverter.IsLittleEndian){Array.Reverse(ip);}string address =String.Join(".", ip.Select(n => n.ToString()));
Você precisa usar um uint, mas esta é a resposta mais correta aqui.
RubberDuck
1
@RubberDuck: Você só precisa usar um uintse quiser os 32 bits de dados como um número sem sinal e intfor capaz de conter as mesmas informações. Se você quiser armazená-lo em um banco de dados e intfor mais adequado, você precisa bigintser capaz de armazená-lo na forma não assinada.
Guffa
1
A uint é uma representação melhor IMO. Um int assinado precisa de um pouco para o sinal, então você perde endereços no topo da faixa. Sim, ele pode conter os mesmos dados, mas será gerado como um número negativo, que não é um IP válido se você digitá-lo na barra de endereço.
RubberDuck
@RubberDuck: Na forma de um, uintvocê também não pode digitá-lo na barra de endereço, primeiro você precisa convertê-lo em um texto para fazer isso. Só porque usar a forma mais simples de transformar um intem texto não produz um endereço IP funcional, não é um bom argumento para não usá-lo.
Guffa
@RubberDuck: Não é um uint, é a representação de texto de um uint.
Guffa
7
Eu encontrei alguns problemas com as soluções descritas, ao enfrentar endereços IP com um valor muito grande. O resultado seria que o byte [0] * 16777216 thingy estouraria e se tornaria um valor int negativo. o que consertou para mim foi a operação de fundição de um tipo simples.
Minha pergunta foi encerrada, não tenho ideia do porquê. A resposta aceita aqui não é a mesma que eu preciso.
Isso me dá o valor inteiro correto para um IP ..
publicdoubleIPAddressToNumber(stringIPaddress){int i;string[] arrDec;double num =0;if(IPaddress==""){return0;}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;}}
Reunimos várias das respostas acima em um método de extensão que lida com o Endianness da máquina e endereços IPv4 que foram mapeados para IPv6.
publicstaticclassIPAddressExtensions{/// <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>publicstaticuintToUint(thisIPAddress address){if(address.AddressFamily==AddressFamily.InterNetwork|| address.IsIPv4MappedToIPv6){var bytes = address.GetAddressBytes();if(BitConverter.IsLittleEndian)Array.Reverse(bytes);returnBitConverter.ToUInt32(bytes,0);}thrownewArgumentOutOfRangeException("address","Address must be IPv4 or IPv4 mapped to IPv6");}}
Testes de unidade:
[TestClass]publicclassIPAddressExtensionsTests{[TestMethod]publicvoidSimpleIp1(){var ip =IPAddress.Parse("0.0.0.15");uint expected =GetExpected(0,0,0,15);Assert.AreEqual(expected, ip.ToUint());}[TestMethod]publicvoidSimpleIp2(){var ip =IPAddress.Parse("0.0.1.15");uint expected =GetExpected(0,0,1,15);Assert.AreEqual(expected, ip.ToUint());}[TestMethod]publicvoidSimpleIpSix1(){var ip =IPAddress.Parse("0.0.0.15").MapToIPv6();uint expected =GetExpected(0,0,0,15);Assert.AreEqual(expected, ip.ToUint());}[TestMethod]publicvoidSimpleIpSix2(){var ip =IPAddress.Parse("0.0.1.15").MapToIPv6();uint expected =GetExpected(0,0,1,15);Assert.AreEqual(expected, ip.ToUint());}[TestMethod]publicvoidHighBits(){var ip =IPAddress.Parse("200.12.1.15").MapToIPv6();uint expected =GetExpected(200,12,1,15);Assert.AreEqual(expected, ip.ToUint());}uintGetExpected(uint a,uint b,uint c,uint d){return(a *256u*256u*256u)+(b *256u*256u)+(c *256u)+(d);}}
Acho que ficaria mais claro se você usasse shift em vez de Math.Pow.
Mehrdad Afshari
Isso lançará uma exceção de estouro se o primeiro for> 127. A resposta de Davy Landman é a melhor maneira de fazer isso.
mhenry1384
int32 é assinado, portanto, retornará um valor negativo> 127 para o primeiro octeto
Mateusz
1
publicboolTryParseIPv4Address(stringvalue,outuint result){IPAddress ipAddress;if(!IPAddress.TryParse(value,out ipAddress)||(ipAddress.AddressFamily!=System.Net.Sockets.AddressFamily.InterNetwork)){
result =0;returnfalse;}
result =BitConverter.ToUInt32(ipAddress.GetAddressBytes().Reverse().ToArray(),0);returntrue;}
O exemplo acima seria o meu caminho. A única coisa que você pode ter que fazer é converter para um UInt32 para fins de exibição ou para fins de string, incluindo usá-lo como um endereço longo na forma de string.
Que é necessário ao usar a função IPAddress.Parse (String). Suspiro.
aqui está uma solução que descobri hoje (deveria ter pesquisado primeiro no Google!):
privatestaticstringIpToDecimal2(string ipAddress){// need a shift counterint shift =3;// loop through the octets and compute the decimal versionvar octets = ipAddress.Split('.').Select(p =>long.Parse(p));return octets.Aggregate(0L,(total, octet)=>(total +(octet <<(shift--*8)))).ToString();}
Estou usando LINQ, lambda e algumas das extensões dos genéricos, portanto, embora produza o mesmo resultado, usa alguns dos novos recursos de linguagem e você pode fazer isso em três linhas de código.
eu tenho a explicação no meu blog se você estiver interessado.
@Davy Ladman, sua solução com shift está correta, mas apenas para ip começando com número menor ou igual a 99, de fato, o primeiro octeto deve ser convertido em longo.
De qualquer forma, converter de volta com o tipo longo é bastante difícil porque armazena 64 bits (não 32 para Ip) e preenche 4 bytes com zeros
o método GetAddressBytes pode retornar os bytes na ordem inversa, dependendo se a máquina é endian ou endian-ness, então a instrução correta pode ser para algumas máquinas: long m_Address = (endereço [0] << 24 | endereço [1] << 16 | endereço [2] << 8 | endereço [3]) & 0x0FFFFFFFF
MiguelSlv
0
Percebi que System.Net.IPAddress tem a propriedade Address (System.Int64) e o construtor, que também aceita o tipo de dados Int64. Portanto, você pode usar isso para converter o endereço IP de / para o formato numérico (embora não seja Int32, mas Int64).
int
s são little-endian na maioria dos sistemas. Portanto, você deve inverter os bytes antes de converter. Veja minha resposta para conversões corretas. Além disso, mesmo para IPv4, umint
não pode conter endereços maiores que127.255.255.255
, por exemplo , o endereço de broadcast, então use auint
.Respostas:
Inteiros não assinados de 32 bits são endereços IPv4. Enquanto isso, o
IPAddress.Address
propriedade, embora obsoleta, é um Int64 que retorna o valor de 32 bits não assinado do endereço IPv4 (o problema é que está na ordem de bytes da rede, então você precisa trocá-lo).Por exemplo, meu google.com local é em
64.233.187.99
. Isso é equivalente a:E realmente, http: // 1089059683 / funciona como esperado (pelo menos no Windows, testado com IE, Firefox e Chrome; embora não funcione no iPhone).
Este é um programa de teste para mostrar ambas as conversões, incluindo a troca de bytes de rede / host:
fonte
Aqui está um par de métodos para converter IPv4 em um número inteiro correto e vice-versa:
Exemplo
Explicação
Os endereços IP estão na ordem da rede (big-endian), enquanto
int
s são little-endian no Windows, portanto, para obter um valor correto, você deve reverter os bytes antes de converter em um sistema little-endian.Além disso, mesmo para
IPv4
anint
não pode conter endereços maiores do que127.255.255.255
, por exemplo, o endereço de broadcast(255.255.255.255)
, então use auint
.fonte
1.1.1.1
porque seu array de bytes é palíndromo. Experimente com os não palíndrômicos como127.0.0.1
ou192.168.1.1
.1.1.1.1
,2.2.2.2
,123.123.123.123
sempre produzir o mesmo resultado. Para a posteridade, veja o violino atualizado: dotnetfiddle.net/aR6fhcSystem.Net.IPAddress
para fazer isso funcionar. Funciona bem!2.1.1.2
seria o mesmo.@Barry Kelly e @Andrew Hare, na verdade, não acho que a multiplicação seja a maneira mais clara de fazer isso (totalmente correto).
Um endereço IP "formatado" Int32 pode ser visto como a seguinte estrutura
Portanto, para converter o endereço IP 64.233.187.99, você pode fazer:
então você pode somar usando + ou você pode binairy ou eles juntos. Resultando em 0x40E9BB63 que é 1089059683. (Na minha opinião, olhando em hexadecimal é muito mais fácil ver os bytes)
Então você pode escrever a função como:
fonte
LayoutKind.Explicit
eFieldOffset
para inverter a ordem em que os bytes são armazenados. Claro, isso só funciona para a arquitetura little endian. Exemplo no github .int
é assinado então se você deslocar 192 por 24 bits você obterá um inteiro negativo então este código é quebrado para octeto alto tendo bit alto em primeiro lugar.Experimente estes:
fonte
Reverse()
retorna void, então você não pode chamáToArray()
-lo (para leitores futuros). Em vez disso, atribua um valor aos bytes invertidos, então você pode chamar ToArray ().IEnumerable
. O código acima está perfeitamente ok.Como ninguém postou o código que usa
BitConverter
e realmente verifica o endianness, aqui vai:e volta:
fonte
uint
se quiser os 32 bits de dados como um número sem sinal eint
for capaz de conter as mesmas informações. Se você quiser armazená-lo em um banco de dados eint
for mais adequado, você precisabigint
ser capaz de armazená-lo na forma não assinada.uint
você também não pode digitá-lo na barra de endereço, primeiro você precisa convertê-lo em um texto para fazer isso. Só porque usar a forma mais simples de transformar umint
em texto não produz um endereço IP funcional, não é um bom argumento para não usá-lo.uint
, é a representação de texto de umuint
.Eu encontrei alguns problemas com as soluções descritas, ao enfrentar endereços IP com um valor muito grande. O resultado seria que o byte [0] * 16777216 thingy estouraria e se tornaria um valor int negativo. o que consertou para mim foi a operação de fundição de um tipo simples.
fonte
O reverso da função de Davy Landman
fonte
Minha pergunta foi encerrada, não tenho ideia do porquê. A resposta aceita aqui não é a mesma que eu preciso.
Isso me dá o valor inteiro correto para um IP ..
fonte
Com o UInt32 no formato little-endian adequado, aqui estão duas funções de conversão simples:
fonte
Reunimos várias das respostas acima em um método de extensão que lida com o Endianness da máquina e endereços IPv4 que foram mapeados para IPv6.
Testes de unidade:
fonte
Se você estava interessado na função, não apenas a resposta aqui é como ela é feita:
com
first
atravésfourth
sendo os segmentos do endereço IPv4.fonte
fonte
O exemplo acima seria o meu caminho. A única coisa que você pode ter que fazer é converter para um UInt32 para fins de exibição ou para fins de string, incluindo usá-lo como um endereço longo na forma de string.
Que é necessário ao usar a função IPAddress.Parse (String). Suspiro.
fonte
aqui está uma solução que descobri hoje (deveria ter pesquisado primeiro no Google!):
Estou usando LINQ, lambda e algumas das extensões dos genéricos, portanto, embora produza o mesmo resultado, usa alguns dos novos recursos de linguagem e você pode fazer isso em três linhas de código.
eu tenho a explicação no meu blog se você estiver interessado.
saúde, -jc
fonte
Acho que isso está errado: "65536" ==> 0.0.255.255 "Deveria ser:" 65535 "==> 0.0.255.255" ou "65536" ==> 0.1.0.0 "
fonte
@Davy Ladman, sua solução com shift está correta, mas apenas para ip começando com número menor ou igual a 99, de fato, o primeiro octeto deve ser convertido em longo.
De qualquer forma, converter de volta com o tipo longo é bastante difícil porque armazena 64 bits (não 32 para Ip) e preenche 4 bytes com zeros
Aproveitar!
Massimo
fonte
Supondo que você tenha um endereço IP em formato de string (por exemplo, 254.254.254.254)
fonte
Saída: 10101005056
fonte
fonte
Percebi que System.Net.IPAddress tem a propriedade Address (System.Int64) e o construtor, que também aceita o tipo de dados Int64. Portanto, você pode usar isso para converter o endereço IP de / para o formato numérico (embora não seja Int32, mas Int64).
fonte
Dê uma olhada em alguns dos exemplos malucos de análise em IPAddress.Parse do .Net: ( 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
fonte