回答:
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));
}
}
次に、IPv4から正しい整数に変換して戻すための 2つの方法を示します。
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アドレスはネットワーク順(ビッグエンディアン)ですが、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/aR6fhc
System.Net.IPAddress
これを機能させるために使用しなければならなかったことに注意したい。よく働く!
2.1.1.2
同じだろう。
@バリー・ケリーと@アンドリュー・ヘア、実際には、乗算はこれを行うための最も明確な方法だとは思いません(完全に正しい)。
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
+を使用してそれらを追加したり、binairyまたはそれらを一緒にしたりできます。その結果、1089059683である0x40E9BB63になります(16進数で見ると、バイトが見やすくなります)。
したがって、関数は次のように書くことができます。
int ipToInt(int first, int second,
int third, int fourth)
{
return (first << 24) | (second << 16) | (third << 8) | (fourth);
}
LayoutKind.Explicit
およびFieldOffset
を使用して、バイトが格納される順序を逆にすることができます。もちろん、これはリトルエンディアンアーキテクチャでのみ機能します。githubの例。
int
署名されていることを指摘する必要があるので、192を24ビットシフトすると負の整数が得られるので、最初に高ビットを持つ高オクテットでこのコードは壊れます。
これを試してください:
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()を呼び出すことができます。
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
32ビットのデータを符号なしの数値として使用したい場合にのみ使用する必要がありint
ます。同じ情報を保持できます。データベースに保存したい場合は、署名なしの形式で保存できるようにするint
必要がありますbigint
。
uint
アドレスバーにも入力できない形式では、まずテキスト形式に変換する必要があります。int
をテキストに変換する最も単純な形式を使用しても機能するIPアドレスが生成されないからといって、IPアドレスを使用しないことは適切ではありません。
uint
ではなく、のテキスト表現ですuint
。
非常に大きな値を持つ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;
}
デイビーランドマンの機能の逆
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;
}
質問は締め切られました。理由はわかりません。ここで受け入れられた答えは、私が必要としているものと同じではありません。
これにより、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;
}
}
適切なリトルエンディアン形式のUInt32を使用した、2つの簡単な変換関数を次に示します。
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();
}
上記の回答のいくつかを、マシンのエンディアンを処理し、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);
}
}
あなたが関数に興味を持っていたなら、ここでの答えだけではなく、それがどのように行われるかです:
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);
}
とfirst
を介してfourth
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));
}
上記の例は私が行く方法です...あなたがしなければならないかもしれない唯一のことは、表示目的、または文字列形式の長いアドレスとして使用することを含む文字列目的のためにUInt32に変換することです。
これは、IPAddress.Parse(String)関数を使用するときに必要なものです。はぁ。
ここに私が今日解決した解決策があります(最初にググったほうがいいです!):
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、ラムダ、ジェネリックのいくつかの拡張機能を使用しているため、同じ結果が得られますが、新しい言語機能のいくつかが使用され、3行のコードで実行できます。
興味があればブログに説明があります。
乾杯、-jc
これは間違っていると思います: "65536" ==> 0.0.255.255 "でなければなりません:" 65535 "==> 0.0.255.255"または "65536" ==> 0.1.0.0 "
@Davy Ladmanシフトを使用したソリューションは正しいですが、99以下の番号で始まるIPの場合のみ、無傷の最初のオクテットをlongにキャストする必要があります。
とにかく、64ビット(Ipの場合は32ではない)を格納し、4バイトをゼロで埋めるので、長い型で元に戻すのは非常に困難です。
static uint ToInt(string addr)
{
return BitConverter.ToUInt32(IPAddress.Parse(addr).GetAddressBytes(), 0);
}
static string ToAddr(uint address)
{
return new IPAddress(address).ToString();
}
楽しい!
マッシモ
var address = IPAddress.Parse("10.0.11.174").GetAddressBytes();
long m_Address = ((address[3] << 24 | address[2] << 16 | address[1] << 8 | address[0]) & 0x0FFFFFFFF);
.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
int
ます。したがって、変換する前にバイトを逆にする必要があります。正しい変換については私の答えを参照してください。また、でもIPv4のために、int
より大きなアドレスを保持することができない127.255.255.255
、例えばので使用し、ブロードキャストアドレスをuint
。