Standart bir IPv4 adresini Tamsayıya dönüştürecek bir işlev arıyorum. Bunun tersini yapacak bir işlev için mevcut bonus puanlar.
Çözüm C # dilinde olmalıdır.
Standart bir IPv4 adresini Tamsayıya dönüştürecek bir işlev arıyorum. Bunun tersini yapacak bir işlev için mevcut bonus puanlar.
Çözüm C # dilinde olmalıdır.
Yanıtlar:
32 bit işaretsiz tamsayı olan IPv4 adresleri. Bu aradaIPAddress.Address
özellik, kullanımdan kaldırılmış olsa da, IPv4 adresinin işaretsiz 32 bit değerini döndüren bir Int64'tür (yakalama, ağ bayt sırasındadır, bu nedenle onu değiştirmeniz gerekir).
Örneğin, yerel google.com adresimde 64.233.187.99
. Bu şuna eşdeğerdir:
64*2^24 + 233*2^16 + 187*2^8 + 99
= 1089059683
Ve gerçekten http: // 1089059683 / beklendiği gibi çalışır (en azından Windows'ta, IE, Firefox ve Chrome ile test edilmiştir; yine de iPhone'da çalışmaz).
Ağ / ana bilgisayar bayt değişimi dahil her iki dönüşümü de gösteren bir test programı aşağıda verilmiştir:
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));
}
}
İşte IPv4'ten doğru bir tam sayıya ve geriye doğru dönüştürmek için bir çift yöntem :
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();
}
Misal
ConvertFromIpAddressToInteger("255.255.255.254"); // 4294967294
ConvertFromIntegerToIpAddress(4294967294); // 255.255.255.254
Açıklama
IP adresleri ağ düzenindedir (big-endian), int
s Windows'da küçük endian iken , bu yüzden doğru bir değer elde etmek için little-endian sistemde dönüştürmeden önce baytları tersine çevirmelisiniz.
Ayrıca, IPv4
bir yayın adresinden int
daha büyük adresler için bile tutulamaz , bu nedenle a kullanın .127.255.255.255
(255.255.255.255)
uint
1.1.1.1
, bayt dizisi palindromik olduğu için girdiniz için bir fark yaratmaz . 127.0.0.1
Veya gibi palindromik olmayanları deneyin 192.168.1.1
.
1.1.1.1
, 2.2.2.2
, 123.123.123.123
her zaman aynı sonucu verir. Gelecek nesil için, güncellenmiş keman sayfasına bakınız: dotnetfiddle.net/aR6fhc
System.Net.IPAddress
. Harika çalışıyor!
2.1.1.2
aynı olacaktır.
@Barry Kelly ve @Andrew Hare, aslında çoğalmanın bunu yapmanın en net yolu olduğunu sanmıyorum (çok doğru).
Int32 "formatlı" bir IP adresi aşağıdaki yapı olarak görülebilir
[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
Yani 64.233.187.99 ip adresini dönüştürmek için şunları yapabilirsiniz:
(64 = 0x40) << 24 == 0x40000000
(233 = 0xE9) << 16 == 0x00E90000
(187 = 0xBB) << 8 == 0x0000BB00
(99 = 0x63) == 0x00000063
---------- =|
0x40E9BB63
böylece bunları + kullanarak ekleyebilir veya binairy veya birlikte kullanabilirsiniz. 1089059683 olan 0x40E9BB63 ile sonuçlanıyor. (Bence onaltılık olarak bakmak baytları görmek çok daha kolay)
Böylece işlevi şu şekilde yazabilirsiniz:
int ipToInt(int first, int second,
int third, int fourth)
{
return (first << 24) | (second << 16) | (third << 8) | (fourth);
}
LayoutKind.Explicit
ve kullanabilirsiniz FieldOffset
. Tabii ki, bu sadece küçük endian mimarisi için çalışıyor. Github'da örnek .
int
imzalandığını belirtmek zorundasınız, böylece 192'i 24 bit kaydırırsanız, negatif tamsayı elde edersiniz, böylece bu kod, ilk etapta yüksek bit olan yüksek sekizli için kırılır.
Şunu deneyin:
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 döndürür, bu yüzden ToArray()
onu arayamazsınız (gelecekteki okuyucular için). Bunun yerine, tersine çevrilmiş baytlara bir değer atayın, ardından ToArray () 'ı çağırabilirsiniz.
IEnumerable
. Yukarıdaki kod tamamen tamam.
Hiç kimse BitConverter
endianness kullanan ve gerçekten kontrol eden kodu göndermediğinden , işte:
byte[] ip = address.Split('.').Select(s => Byte.Parse(s)).ToArray();
if (BitConverter.IsLittleEndian) {
Array.Reverse(ip);
}
int num = BitConverter.ToInt32(ip, 0);
ve geri:
byte[] ip = BitConverter.GetBytes(num);
if (BitConverter.IsLittleEndian) {
Array.Reverse(ip);
}
string address = String.Join(".", ip.Select(n => n.ToString()));
uint
32 bitlik veriyi işaretsiz bir sayı olarak istiyorsanız, bir kullanmanız gerekir int
, aynı bilgiyi tutabilir. Bir veritabanında depolamak istiyorsanız ve int
daha uygunsa, bigint
imzasız biçimde saklayabilmeniz için a gerekir .
uint
adres çubuğuna da yazamazsınız , bunu yapmak için önce metin formuna dönüştürmeniz gerekir. Sırf bir int
metne dönüştürmenin en basit biçimini kullanmak, çalışan bir IP adresi üretmediği için, onu kullanmamak için iyi bir argüman değildir.
uint
, bir uint
.
Çok büyük bir değere sahip IP Adresleriyle karşılaştığımda açıklanan çözümlerde bazı sorunlarla karşılaştım. Sonuç, bayt [0] * 16777216 şeyinin taşması ve negatif bir int değerine dönüşmesi olacaktır. benim için bunu düzelten şey, basit bir tür döküm işlemi.
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;
}
Davy Landman'ın işlevinin tersi
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;
}
Sorum kapandı, neden olduğuna dair hiçbir fikrim yok. Burada kabul edilen cevap ihtiyacım olanla aynı değil.
Bu bana bir IP için doğru tamsayı değerini verir.
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;
}
}
UInt32 ile uygun küçük endian biçiminde, işte iki basit dönüştürme işlevi:
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();
}
Yukarıdaki yanıtlardan birkaçı, makinenin Endianness'ini işleyen ve IPv6'ya eşlenen IPv4 adreslerini işleyen bir uzatma yönteminde toplandı.
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");
}
}
Birim testleri:
[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);
}
}
Fonksiyonla ilgileniyorsanız, sadece buradaki cevap değil, nasıl yapıldığıdır:
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);
}
ile first
aracılığıyla fourth
IPv4 adres bölümleri olmak.
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;
}
public static Int32 getLongIPAddress(string ipAddress)
{
return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0));
}
Yukarıdaki örnek benim gideceğim yol olabilir .. Yapmanız gereken tek şey, görüntüleme amacıyla veya dizge biçiminde uzun bir adres olarak kullanmak da dahil olmak üzere dize amacıyla bir UInt32'ye dönüştürmektir.
IPAddress.Parse (String) işlevini kullanırken ihtiyaç duyulan şey budur. İç çekmek.
İşte bugün üzerinde çalıştığım bir çözüm (önce googled olmalıydı!)
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 ve jeneriklerdeki bazı uzantıları kullanıyorum, bu yüzden aynı sonucu üretirken, bazı yeni dil özelliklerini kullanıyor ve bunu üç satır kodda yapabilirsiniz.
eğer ilgilenirseniz blogumda bir açıklama var.
şerefe, -jc
Bunun yanlış olduğunu düşünüyorum: "65536" ==> 0.0.255.255 "" 65535 "==> 0.0.255.255" veya "65536" ==> 0.1.0.0 "olmalıdır
@Davy Ladman vardiyalı çözümünüz doğru, ancak sadece 99'dan küçük veya eşit sayı ile başlayan ip için infact ilk oktekt uzun süre kullanılmalıdır.
Her neyse, uzun tiple geri dönüştürmek oldukça zordur çünkü 64 bit depolayın (Ip için 32 değil) ve 4 baytı sıfırlarla doldurun
static uint ToInt(string addr)
{
return BitConverter.ToUInt32(IPAddress.Parse(addr).GetAddressBytes(), 0);
}
static string ToAddr(uint address)
{
return new IPAddress(address).ToString();
}
Zevk almak!
Massimo
var address = IPAddress.Parse("10.0.11.174").GetAddressBytes();
long m_Address = ((address[3] << 24 | address[2] << 16 | address[1] << 8 | address[0]) & 0x0FFFFFFFF);
int
s çoğu sistemde küçüktür. Dolayısıyla, dönüştürmeden önce baytları tersine çevirmelisiniz. Bkz Cevabımı doğru dönüşümler için. Ayrıca, IPv4 için bile , örneğin yayın adresindenint
daha büyük adresler tutulamaz , bu nedenle a .127.255.255.255
uint