Saya mencari fungsi yang akan mengubah alamat IPv4 standar menjadi Integer. Poin bonus tersedia untuk fungsi yang melakukan kebalikannya.
Solusi harus dalam C #.
Saya mencari fungsi yang akan mengubah alamat IPv4 standar menjadi Integer. Poin bonus tersedia untuk fungsi yang melakukan kebalikannya.
Solusi harus dalam C #.
Jawaban:
Integer 32-bit unsigned adalah alamat IPv4. Sementara itu, IPAddress.Address
properti, meski tidak digunakan lagi, adalah Int64 yang mengembalikan nilai 32-bit unsigned dari alamat IPv4 (tangkapannya adalah, dalam urutan byte jaringan, jadi Anda perlu menukarnya).
Misalnya, google.com lokal saya ada di 64.233.187.99
. Itu setara dengan:
64*2^24 + 233*2^16 + 187*2^8 + 99
= 1089059683
Dan memang, http: // 1089059683 / berfungsi seperti yang diharapkan (setidaknya di Windows, diuji dengan IE, Firefox dan Chrome; meskipun tidak berfungsi di iPhone).
Berikut adalah program uji untuk menunjukkan kedua konversi, termasuk pertukaran byte jaringan / host:
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));
}
}
Berikut adalah sepasang metode untuk mengonversi dari IPv4 ke bilangan bulat yang benar dan sebaliknya:
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();
}
Contoh
ConvertFromIpAddressToInteger("255.255.255.254"); // 4294967294
ConvertFromIntegerToIpAddress(4294967294); // 255.255.255.254
Penjelasan
Alamat IP berada dalam urutan jaringan (big-endian), sedangkan int
s adalah little-endian pada Windows, jadi untuk mendapatkan nilai yang benar, Anda harus membalikkan byte sebelum mengonversi pada sistem little-endian.
Juga, bahkan untuk IPv4
, an int
tidak dapat menyimpan alamat yang lebih besar dari 127.255.255.255
, misalnya alamat broadcast (255.255.255.255)
, jadi gunakan a uint
.
1.1.1.1
karena array byte-nya adalah palindromik. Coba dengan yang non-palindromik seperti 127.0.0.1
atau 192.168.1.1
.
1.1.1.1
, 2.2.2.2
, 123.123.123.123
selalu menghasilkan hasil yang sama. Untuk anak cucu, lihat biola yang diperbarui: dotnetfiddle.net/aR6fhc
System.Net.IPAddress
agar ini berfungsi. Bekerja dengan baik!
2.1.1.2
halnya.
@Barry Kelly dan @Andrew Hare, sebenarnya, menurut saya mengalikan adalah cara paling jelas untuk melakukan ini (semuanya benar).
Alamat IP "diformat" Int32 dapat dilihat sebagai struktur berikut
[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
Jadi untuk mengubah alamat ip 64.233.187.99 Anda bisa melakukan:
(64 = 0x40) << 24 == 0x40000000
(233 = 0xE9) << 16 == 0x00E90000
(187 = 0xBB) << 8 == 0x0000BB00
(99 = 0x63) == 0x00000063
---------- =|
0x40E9BB63
jadi Anda bisa menambahkannya menggunakan + atau Anda bisa binairy atau bersama-sama. Menghasilkan 0x40E9BB63 yaitu 1089059683. (Menurut pendapat saya, mencari di hex jauh lebih mudah untuk melihat byte)
Jadi Anda bisa menulis fungsinya sebagai:
int ipToInt(int first, int second,
int third, int fourth)
{
return (first << 24) | (second << 16) | (third << 8) | (fourth);
}
LayoutKind.Explicit
dan FieldOffset
membalik urutan penyimpanan byte. Tentu saja, itu hanya berfungsi untuk arsitektur little endian. Contoh di github .
int
ditandatangani sehingga jika Anda menggeser 192 dengan 24 bit Anda akan mendapatkan bilangan bulat negatif sehingga kode ini rusak untuk oktet tinggi yang memiliki bit tinggi di tempat pertama.
Coba yang ini:
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()
pengembalian tidak berlaku, jadi Anda tidak dapat memanggilnya ToArray()
(untuk pembaca mendatang). Sebagai gantinya, tetapkan nilai ke byte yang dibalik, lalu Anda dapat memanggil ToArray ().
IEnumerable
. Kode di atas sangat oke.
Karena tidak ada yang memposting kode yang menggunakan BitConverter
dan benar-benar memeriksa endianness, ini dia:
byte[] ip = address.Split('.').Select(s => Byte.Parse(s)).ToArray();
if (BitConverter.IsLittleEndian) {
Array.Reverse(ip);
}
int num = BitConverter.ToInt32(ip, 0);
dan kembali:
byte[] ip = BitConverter.GetBytes(num);
if (BitConverter.IsLittleEndian) {
Array.Reverse(ip);
}
string address = String.Join(".", ip.Select(n => n.ToString()));
uint
jika Anda ingin 32 bit data sebagai nomor tak bertanda tangan, dan int
mampu menyimpan informasi yang sama. Jika Anda ingin menyimpannya dalam database dan int
lebih cocok, Anda membutuhkannya bigint
agar dapat menyimpannya dalam bentuk unsigned.
uint
Anda juga tidak dapat mengetikkannya di bilah alamat, Anda harus mengonversinya terlebih dahulu ke dalam bentuk teks untuk melakukannya. Hanya karena menggunakan bentuk paling sederhana untuk mengubah sebuah int
teks tidak menghasilkan alamat IP yang berfungsi bukanlah argumen yang baik untuk tidak menggunakannya.
uint
, itu representasi teks dari sebuah uint
.
Saya mengalami beberapa masalah dengan solusi yang dijelaskan, saat menghadapi Alamat IP dengan nilai yang sangat besar. Hasilnya adalah, bahwa thingy byte [0] * 16777216 akan meluap dan menjadi nilai int negatif. apa yang memperbaikinya untuk saya, adalah operasi pengecoran tipe sederhana.
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;
}
Kebalikan dari fungsi 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;
}
Pertanyaan saya ditutup, saya tidak tahu mengapa. Jawaban yang diterima di sini tidak sama dengan yang saya butuhkan.
Ini memberi saya nilai integer yang benar untuk sebuah 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;
}
}
Dengan UInt32 dalam format little-endian yang tepat, berikut dua fungsi konversi sederhana:
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();
}
Mengumpulkan beberapa jawaban di atas menjadi metode ekstensi yang menangani Ketahanan mesin dan menangani alamat IPv4 yang dipetakan ke IPv6.
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");
}
}
Tes unit:
[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);
}
}
Jika Anda tertarik dengan fungsinya, bukan hanya jawabannya di sini adalah cara melakukannya:
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);
}
dengan first
melalui fourth
menjadi segmen dari alamat IPv4.
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));
}
Contoh di atas akan menjadi cara saya pergi .. Satu-satunya hal yang mungkin harus Anda lakukan adalah mengubah ke UInt32 untuk tujuan tampilan, atau tujuan string termasuk menggunakannya sebagai alamat panjang dalam bentuk string.
Yang diperlukan saat menggunakan fungsi IPAddress.Parse (String). Mendesah.
inilah solusi yang saya kerjakan hari ini (seharusnya sudah googling dulu!):
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();
}
Saya menggunakan LINQ, lambda dan beberapa ekstensi pada generik, jadi meskipun menghasilkan hasil yang sama, ia menggunakan beberapa fitur bahasa baru dan Anda dapat melakukannya dalam tiga baris kode.
Saya punya penjelasan di blog saya jika Anda tertarik.
tepuk tangan, -jc
Saya pikir ini salah: "65536" ==> 0.0.255.255 "Seharusnya:" 65535 "==> 0.0.255.255" atau "65536" ==> 0.1.0.0 "
@Davy Ladman solusi Anda dengan shift sudah benar tetapi hanya untuk ip yang dimulai dengan angka kurang atau sama dengan 99, sebenarnya oktek pertama harus dibuang sampai panjang.
Pokoknya mengkonversi kembali dengan tipe lama cukup sulit karena simpan 64 bit (bukan 32 untuk Ip) dan isi 4 byte dengan nol
static uint ToInt(string addr)
{
return BitConverter.ToUInt32(IPAddress.Parse(addr).GetAddressBytes(), 0);
}
static string ToAddr(uint address)
{
return new IPAddress(address).ToString();
}
Nikmati!
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 adalah little-endian pada kebanyakan sistem. Jadi, Anda harus membalik byte sebelum mengonversi. Lihat jawaban saya untuk konversi yang benar. Juga, bahkan untuk IPv4, anint
tidak dapat menyimpan alamat yang lebih besar dari127.255.255.255
, misalnya alamat broadcast, jadi gunakan auint
.