ВНИМАНИЕ : целые числа, полученные в результате принятого ответа, будут неправильными , потому что IP-адреса находятся в сетевом порядке (с прямым порядком байтов), а intв большинстве систем с прямым порядком байтов. Поэтому перед преобразованием вы должны перевернуть байты. Смотрите мой ответ для правильных преобразований. Кроме того, даже для IPv4 не intможет содержать адреса больше, чем 127.255.255.255, например, широковещательный адрес, поэтому используйте расширение uint.
Саеб Амини,
Ответы:
138
32-битные целые числа без знака - это адреса IPv4. Между тем, это IPAddress.Addressсвойство, хотя и не рекомендуется, представляет собой Int64, которое возвращает беззнаковое 32-битное значение IPv4-адреса (загвоздка в том, что он находится в сетевом порядке байтов, поэтому вам нужно поменять его местами).
Например, мой локальный 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;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));}}
IP-адреса расположены в сетевом порядке (с прямым порядком байтов), а ints - с прямым порядком байтов в Windows, поэтому для получения правильного значения вы должны перевернуть байты перед преобразованием в системе с прямым порядком байтов.
Кроме того, даже для IPv4, не intможет содержать адреса больше, чем 127.255.255.255, например, широковещательный адрес (255.255.255.255), поэтому используйте uint.
На самом деле, похоже, что это не имеет значения для Windows, использующей .NET - не уверен в Mono. См. Dotnetfiddle.net/cBIOj2
Джесси
2
@Jesse это не имеет значения для вашего ввода, 1.1.1.1потому что его байтовый массив является палиндромным. Попробуйте использовать непалиндромные, например 127.0.0.1или 192.168.1.1.
Саеб Амини
Я вижу проблему. Повторные числа , такие как 1.1.1.1, 2.2.2.2, 123.123.123.123всегда дают тот же результат. Для потомков см. Обновленную скрипку: dotnetfiddle.net/aR6fhc
Джесси,
Хотел бы отметить, что мне пришлось использовать, System.Net.IPAddressчтобы это работало. Прекрасно работает!
Shrout1 06
1
@Jesse, это не только для повторяющихся чисел, но и для всех палиндромных IP-адресов. Так 2.1.1.2было бы тоже самое.
Саеб Амини
40
@Barry Kelly и @Andrew Hare, на самом деле, я не думаю, что умножение - самый очевидный способ сделать это (хотя и правильно).
"Форматированный" IP-адрес Int32 можно рассматривать как следующую структуру
[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
Итак, чтобы преобразовать IP-адрес 64.233.187.99, вы можете сделать:
чтобы вы могли сложить их, используя +, или вы могли бы binairy или их вместе. Результатом является 0x40E9BB63, который равен 1089059683. (На мой взгляд, глядя в шестнадцатеричном формате, намного легче увидеть байты)
Итак, вы можете написать функцию как:
int ipToInt(int first,int second,int third,int fourth){return(first <<24)|(second <<16)|(third <<8)|(fourth);}
Я считаю, что ip были определены таким образом, чтобы специально разрешить такое поведение ... битовые сдвиги намного эффективнее на большинстве микропроцессоров, чем muls и add.
Ape-inago,
1
Умножение @Ape-inago на постоянную степень двойки обычно оптимизируется в битовые сдвиги, fwiw.
Барри Келли
Вместо сдвига битов вы можете использовать LayoutKind.Explicitи FieldOffsetдля изменения порядка, в котором хранятся байты. Конечно, это работает только для архитектуры с прямым порядком байтов. Пример на гитхабе .
RubberDuck
2
Следует отметить, что intэто подписано, поэтому, если вы сдвинете 192 на 24 бита, вы получите отрицательное целое число, поэтому этот код нарушается для старшего октета, имеющего высокий бит на первом месте.
Reverse()возвращает void, поэтому вы не можете ToArray()его использовать (для будущих читателей). Вместо этого присвойте значение обратным байтам, затем вы можете вызвать ToArray ().
Эрик Филипс
1
Reverse () - это метод расширения IEnumerable. Код выше в порядке.
Ant
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()));
Вам нужно использовать uint, но это наиболее правильный ответ.
RubberDuck
1
@RubberDuck: вам нужно использовать, только uintесли вы хотите, чтобы 32 бита данных были беззнаковым числом, intон может хранить ту же информацию. Если вы хотите сохранить его в базе данных, что intлучше подходит, вам понадобится, bigintчтобы иметь возможность хранить его в неподписанной форме.
Guffa
1
Uint - лучшее представление IMO. Для подписанного int требуется немного для знака, поэтому вы теряете адреса в самом верху диапазона. Да, он может содержать те же данные, но будет выводиться как отрицательное число, которое не является действительным IP-адресом, если вы введете его в адресную строку.
RubberDuck
@RubberDuck: в форме, которую uintвы также не можете ввести в адресной строке, вам сначала нужно преобразовать ее в текстовую форму, чтобы сделать это. Тот факт, что использование простейшей формы преобразования intв текст не приводит к созданию рабочего IP-адреса, не является хорошим аргументом в пользу его отказа .
Guffa
@RubberDuck: Это не файл uint, это текстовое представление uint.
Guffa
7
Я столкнулся с некоторыми проблемами с описанными решениями, когда сталкивался с IP-адресами с очень большим значением. Результатом будет то, что байт [0] * 16777216 будет переполнен и станет отрицательным значением int. что исправило это для меня, так это простая операция приведения типов.
Мой вопрос был закрыт, я не знаю почему. Принятый здесь ответ отличается от того, что мне нужно.
Это дает мне правильное целочисленное значение для 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;}}
Пока вы можете выполнять преобразование в обоих направлениях, я не понимаю, почему выходной номер должен быть правильным, если он согласован.
GateKiller
Зависит от того, для чего вы хотите использовать номер. Вы не можете использовать другое преобразование для выполнения запросов> = и <= для поиска IP ..
Coolcoder,
2
Имея UInt32 в правильном формате с прямым порядком байтов, вот две простые функции преобразования:
Собрал несколько из приведенных выше ответов в метод расширения, который обрабатывает порядок байтов машины и обрабатывает адреса IPv4, которые были сопоставлены с 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");}}
Модульные тесты:
[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);}}
Думаю, было бы более понятно, если бы вы использовали shift вместо Math.Pow.
Mehrdad Afshari
Это вызовет исключение переполнения, если first> 127. Ответ Дэви Лэндмана - лучший способ сделать это.
mhenry1384
int32 подписан, поэтому он вернет отрицательное значение> 127 для первого октета
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;}
Приведенный выше пример - это то, что я использую ... Единственное, что вам, возможно, придется сделать, это преобразовать в UInt32 для целей отображения или строковых целей, включая использование его как длинного адреса в строковой форме.
Это то, что нужно при использовании функции IPAddress.Parse (String). Вздох.
вот решение, которое я разработал сегодня (сначала нужно было погуглить!):
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();}
Я использую LINQ, лямбда и некоторые расширения для универсальных шаблонов, поэтому, хотя он дает тот же результат, он использует некоторые из новых языковых функций, и вы можете сделать это в трех строках кода.
У меня есть объяснение в моем блоге, если вам интересно.
@Davy Ladman ваше решение со сдвигом является коррентным, но только для ip, начиная с номера меньше или равного 99, фактически первый октект должен быть увеличен до long.
В любом случае преобразовать обратно с длинным типом довольно сложно, потому что хранить 64 бита (не 32 для Ip) и заполнять 4 байта нулями
метод GetAddressBytes может возвращать байты в обратном порядке, в зависимости от того, является ли машина прямым или прямым порядком байтов, поэтому для некоторых компьютеров может быть правильным выражение: long m_Address = (address [0] << 24 | address [1] << 16 | адрес [2] << 8 | адрес [3]) & 0x0FFFFFFFF
MiguelSlv
0
Я заметил, что System.Net.IPAddress имеет свойство Address (System.Int64) и конструктор, которые также принимают тип данных Int64. Таким образом, вы можете использовать это для преобразования IP-адреса в / из числового (хотя и не Int32, а Int64) формата.
int
в большинстве систем с прямым порядком байтов. Поэтому перед преобразованием вы должны перевернуть байты. Смотрите мой ответ для правильных преобразований. Кроме того, даже для IPv4 неint
может содержать адреса больше, чем127.255.255.255
, например, широковещательный адрес, поэтому используйте расширениеuint
.Ответы:
32-битные целые числа без знака - это адреса IPv4. Между тем, это
IPAddress.Address
свойство, хотя и не рекомендуется, представляет собой Int64, которое возвращает беззнаковое 32-битное значение IPv4-адреса (загвоздка в том, что он находится в сетевом порядке байтов, поэтому вам нужно поменять его местами).Например, мой локальный google.com находится по адресу
64.233.187.99
. Это эквивалентно:И действительно, http: // 1089059683 / работает должным образом (по крайней мере, в Windows, протестировано с IE, Firefox и Chrome; однако не работает на iPhone).
Вот тестовая программа, показывающая оба преобразования, включая обмен байтами сеть / хост:
источник
Вот пара методов преобразования IPv4 в правильное целое число и обратно:
пример
Объяснение
IP-адреса расположены в сетевом порядке (с прямым порядком байтов), а
int
s - с прямым порядком байтов в Windows, поэтому для получения правильного значения вы должны перевернуть байты перед преобразованием в системе с прямым порядком байтов.Кроме того, даже для
IPv4
, неint
может содержать адреса больше, чем127.255.255.255
, например, широковещательный адрес(255.255.255.255)
, поэтому используйтеuint
.источник
1.1.1.1
потому что его байтовый массив является палиндромным. Попробуйте использовать непалиндромные, например127.0.0.1
или192.168.1.1
.1.1.1.1
,2.2.2.2
,123.123.123.123
всегда дают тот же результат. Для потомков см. Обновленную скрипку: dotnetfiddle.net/aR6fhcSystem.Net.IPAddress
чтобы это работало. Прекрасно работает!2.1.1.2
было бы тоже самое.@Barry Kelly и @Andrew Hare, на самом деле, я не думаю, что умножение - самый очевидный способ сделать это (хотя и правильно).
"Форматированный" IP-адрес Int32 можно рассматривать как следующую структуру
Итак, чтобы преобразовать IP-адрес 64.233.187.99, вы можете сделать:
чтобы вы могли сложить их, используя +, или вы могли бы binairy или их вместе. Результатом является 0x40E9BB63, который равен 1089059683. (На мой взгляд, глядя в шестнадцатеричном формате, намного легче увидеть байты)
Итак, вы можете написать функцию как:
источник
LayoutKind.Explicit
иFieldOffset
для изменения порядка, в котором хранятся байты. Конечно, это работает только для архитектуры с прямым порядком байтов. Пример на гитхабе .int
это подписано, поэтому, если вы сдвинете 192 на 24 бита, вы получите отрицательное целое число, поэтому этот код нарушается для старшего октета, имеющего высокий бит на первом месте.Попробуйте эти:
источник
Reverse()
возвращает void, поэтому вы не можетеToArray()
его использовать (для будущих читателей). Вместо этого присвойте значение обратным байтам, затем вы можете вызвать ToArray ().IEnumerable
. Код выше в порядке.Поскольку никто не опубликовал код, который использует
BitConverter
и фактически проверяет порядок байтов, вот что:и назад:
источник
uint
если вы хотите, чтобы 32 бита данных были беззнаковым числом,int
он может хранить ту же информацию. Если вы хотите сохранить его в базе данных, чтоint
лучше подходит, вам понадобится,bigint
чтобы иметь возможность хранить его в неподписанной форме.uint
вы также не можете ввести в адресной строке, вам сначала нужно преобразовать ее в текстовую форму, чтобы сделать это. Тот факт, что использование простейшей формы преобразованияint
в текст не приводит к созданию рабочего IP-адреса, не является хорошим аргументом в пользу его отказа .uint
, это текстовое представлениеuint
.Я столкнулся с некоторыми проблемами с описанными решениями, когда сталкивался с IP-адресами с очень большим значением. Результатом будет то, что байт [0] * 16777216 будет переполнен и станет отрицательным значением int. что исправило это для меня, так это простая операция приведения типов.
источник
Обратная функция Дэви Лэндмана
источник
Мой вопрос был закрыт, я не знаю почему. Принятый здесь ответ отличается от того, что мне нужно.
Это дает мне правильное целочисленное значение для IP.
источник
Имея UInt32 в правильном формате с прямым порядком байтов, вот две простые функции преобразования:
источник
Собрал несколько из приведенных выше ответов в метод расширения, который обрабатывает порядок байтов машины и обрабатывает адреса IPv4, которые были сопоставлены с IPv6.
Модульные тесты:
источник
Если вас интересовала функция, а не просто ответ, вот как это делается:
с
first
помощьюfourth
того , что сегменты адреса IPv4.источник
источник
Приведенный выше пример - это то, что я использую ... Единственное, что вам, возможно, придется сделать, это преобразовать в UInt32 для целей отображения или строковых целей, включая использование его как длинного адреса в строковой форме.
Это то, что нужно при использовании функции IPAddress.Parse (String). Вздох.
источник
вот решение, которое я разработал сегодня (сначала нужно было погуглить!):
Я использую LINQ, лямбда и некоторые расширения для универсальных шаблонов, поэтому, хотя он дает тот же результат, он использует некоторые из новых языковых функций, и вы можете сделать это в трех строках кода.
У меня есть объяснение в моем блоге, если вам интересно.
ура, -jc
источник
Я считаю, что это неправильно: "65536" ==> 0.0.255.255 "Должно быть:" 65535 "==> 0.0.255.255" или "65536" ==> 0.1.0.0 "
источник
@Davy Ladman ваше решение со сдвигом является коррентным, но только для ip, начиная с номера меньше или равного 99, фактически первый октект должен быть увеличен до long.
В любом случае преобразовать обратно с длинным типом довольно сложно, потому что хранить 64 бита (не 32 для Ip) и заполнять 4 байта нулями
Наслаждайтесь!
Массимо
источник
Предполагая, что у вас есть IP-адрес в строковом формате (например, 254.254.254.254)
источник
Выход: 10101005056
источник
источник
Я заметил, что System.Net.IPAddress имеет свойство Address (System.Int64) и конструктор, которые также принимают тип данных Int64. Таким образом, вы можете использовать это для преобразования IP-адреса в / из числового (хотя и не Int32, а Int64) формата.
источник
Взгляните на некоторые безумные примеры синтаксического анализа в IPAddress.Parse .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
источник