私のサーバー アプリでは、IP アドレスがブラックリストに含まれているかどうかを確認する必要があります。
IP アドレスを比較する最も効率的な方法は何ですか? IPアドレスを整数に変換して比較するのは効率的でしょうか?
私のサーバー アプリでは、IP アドレスがブラックリストに含まれているかどうかを確認する必要があります。
IP アドレスを比較する最も効率的な方法は何ですか? IPアドレスを整数に変換して比較するのは効率的でしょうか?
使用している言語によって異なりますが、IP アドレスは通常、少なくともネットワーク層では 32 ビットの符号なし整数として格納されるため、比較は非常に高速です。そうでない場合でも、高性能のパケット交換アプリケーションを設計している場合を除き、パフォーマンスのボトルネックにはなりません。時期尚早の最適化を避ける - テスト容易性とスケーラビリティのためにプログラムを設計し、パフォーマンスの問題がある場合は、プロファイラーを使用してボトルネックがどこにあるかを確認できます。
編集: 明確にするために、IPv4 アドレスは 32 ビット整数とネットマスク (IP アドレスの比較には必要ありません) として格納されます。より新しく、現在はよりまれな IPv6 を使用している場合、アドレスは 128 ビット長になります。
128 ビットの IPv6 アドレスを扱い始めるまでは、32 ビットの整数を使用するのがよいでしょう。
static public bool IsEqual(string ToCompare,
string CompareAgainst)
{
return IPAddressToLongBackwards(ToCompare)==IPAddressToLongBackwards(CompareAgainst);
}
static private uint IPAddressToLongBackwards(string IPAddr)
{
System.Net.IPAddress oIP=System.Net.IPAddress.Parse(IPAddr);
byte[] byteIP=oIP.GetAddressBytes();
uint ip=(uint)byteIP[0]<<24;
ip+=(uint)byteIP[1]<<16;
ip+=(uint)byteIP[2]<<8;
ip+=(uint)byteIP[3];
return ip;
}
私の理解が正しければ、これは 2 つの IP アドレスを比較するためのコードです。これが欲しいですか?さらに、次のようなことができます。
static public bool IsGreater(string ToCompare,
string CompareAgainst)
{
return IPAddressToLongBackwards(ToCompare)>
IPAddressToLongBackwards(CompareAgainst);
}
アドレスバイトを取得したためです。
それをテキスト文字列として比較するか、int を int に変換して int として比較する必要があるということですか?
これは通常、この種のルックアップのボトルネックではありません。両方の方法を実装して、どちらがより速く実行されるかを確認することができます。
IP アドレス ルックアップの実際の問題は、通常、乱数だけでなく IP アドレスを扱っているという事実を利用して、効率的なクエリを作成することです。これを達成するには、 LC trieを検索できます。
明らかに、ブラックリストに数万または数百万のエントリが含まれている場合にのみ、これに関心があるはずです。エントリが 10 ~ 20 個しかない場合は、線形検索を優先する必要があります。実際、より興味深い質問は、テキスト比較と整数比較です。
はい、効率的であることがわかりました。ただし、長くなります。もちろん、ブラックリストに登録された IP を整数形式でインデックス化する必要があります。
Radix または PATRICIA Trie は、これに最適な構造です。
flow-tools の C ソースを確認してください: http://www.splintered.net/sw/flow-tools/
私は何年も前にこれに取り組みました。
私はかつて、IP アドレスを 4 つの int として保存することは本当に良いことだと誰かが考えていたコードを継承しました。
それらをデータベースに文字列として保持する方がはるかに簡単で、必要なインデックスは 1 つだけでした。4 列の整数ではなく、SQL Server が文字列にインデックスを付けることができることに驚かれることでしょう。しかし、この IP リストはブラックリストに登録するためのものではありませんでした。データベースの往復にはかなりのコストがかかります。
データベースが過剰な場合は、それらをメモリ内の辞書に保存しますが、比較する必要がある数がわからないため、これは推測に過ぎません。ほとんどのハッシュコードは 32 ビットの int であり、IPv4 アドレスは 32 ビットであるため、IP アドレス自体が適切なハッシュコードである可能性があります。
しかし、他の人が指摘しているように、最善の選択肢は、サーバーの負荷を減らして専用のハードウェアを購入することかもしれません. おそらく、最近ブラックリストに登録された IP をメモリに保持し、定期的に新しい IP をルーターに発行します。
ルーター内にソフトウェアを作成しようとしている場合は、データ構造の本を探し出して、b ツリーのようなものを作成する必要があります。
ブラックリストの IP へのドライバー レベルで着信 TCP/IP 接続を禁止する PeerGuardian などのツールを使用します。非常に安全で、コードは必要ありません (ほぼ間違いなく、コードが必要ないため、非常に安全です)。
私はこれを行い、テストしました.unsigned int(32ビット)を使用するのが最速です-これを文字列表現と比較していると仮定しています。
テーブルを作成するときに役立つもう 1 つのことは、過去に LowIP と HighIP の 2 つの列がありました。そうすれば、IP の範囲全体を 1 つのレコード エントリでブラックリストに登録でき、範囲内の IP をチェックすることで良好なパフォーマンスを得ることができます。
効率性に関して既存の問題がありますか?
もしそうなら、必ずコード(または疑似コード)を投稿してください。そうすれば、死体を選ぶことができます.
そうでない場合は、ソートされたリストにエントリを保存し、環境の既存の and を使用するなど、簡単なことを試すことをお勧めしSort()
ますFind()
。
整数比較は、文字列比較よりもはるかに高速です。
整数をソートされたリストに格納すると、ソートされていないリストよりも高速に見つけることができます。
IP アドレスを文字列として受け取った場合、整数表現に変換するよりも文字列と比較する方が効率的かもしれません
しかし、この操作で数ミリ秒 (ナノ秒!) が問題になる場合は、両方のソリューションを確実にプロファイルします;-)