ファイル内のIPアドレスとポートを管理するための優れた高速な方法を探しています。IPとポートの2つの列があり、DBを使用せずにファイル内にあるDBテーブルの一種。
追加、削除、更新をサポートする必要があります。並行性は気にしません。
以下に、あなたのタスクを完了するために来る人もいます。厳密に要点を絞ろうとしたので、何か足りないのかもしれません。
IPとポートのペアを保持するために「Record」クラスを作成します
class Record : IPEndPoint, IComparable<Record>
{
internal long Offset { get; set; }
public bool Deleted { get; internal set; }
public Record() : base(0, 0)
{
Offset = -1;
Deleted = false;
}
public int CompareTo(Record other)
{
if (this.Address == other.Address && this.Address == other.Address )
return 0;
else if (this.Address == other.Address)
return this.Port.CompareTo(other.Port);
else
return
BitConverter.ToInt32(this.Address.GetAddressBytes(), 0).CompareTo(
BitConverter.ToInt32(other.Address.GetAddressBytes(), 0));
}
}
class RecordComparer : IComparer<Record>
{
public int Compare(Record x, Record y)
{
return x.CompareTo(y);
}
}
...そしてデータファイルの相互作用を管理するための「DatabaseFile」クラス。
class DatabaseFile : IDisposable
{
private FileStream file;
private static int RecordSize = 7;
private static byte[] Deleted = new byte[] { 42 };
private static byte[] Undeleted = new byte[] { 32 };
public DatabaseFile(string filename)
{
file = new FileStream(filename,
FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
}
public IEnumerable<Record> Locate(Predicate<Record> record)
{
file.Seek(0, SeekOrigin.Begin);
while (file.Position < file.Length)
{
long offset = file.Position;
byte[] buffer = new byte[DatabaseFile.RecordSize];
file.Read(buffer, 0, DatabaseFile.RecordSize);
Record current = Build(offset, buffer);
if (record.Invoke(current))
yield return current;
}
}
public void Append(Record record)
{
// should I look for duplicated values? i dunno
file.Seek(0, SeekOrigin.End);
record.Deleted = false;
record.Offset = file.Position;
Write(record);
}
public void Delete(Record record)
{
if (record.Offset == -1) return;
file.Seek(record.Offset, SeekOrigin.Begin);
record.Deleted = true;
Write(record);
}
public void Update(Record record)
{
if (record.Offset == -1)
{
Append(record);
}
else
{
file.Seek(record.Offset, SeekOrigin.Begin);
Write(record);
}
}
private void Write(Record record)
{
file.Write(GetBytes(record), 0, DatabaseFile.RecordSize);
}
private Record Build(long offset, byte[] data)
{
byte[] ipAddress = new byte[4];
Array.Copy(data, 1, ipAddress, 0, ipAddress.Length);
return new Record
{
Offset = offset,
Deleted = (data[0] == DatabaseFile.Deleted[0]),
Address = new IPAddress(ipAddress),
Port = BitConverter.ToInt16(data, 5)
};
}
private byte[] GetBytes(Record record)
{
byte[] returnValue = new byte[DatabaseFile.RecordSize];
Array.Copy(
record.Deleted ? DatabaseFile.Deleted : DatabaseFile.Undeleted, 0,
returnValue, 0, 1);
Array.Copy(record.Address.GetAddressBytes(), 0,
returnValue, 1, 4);
Array.Copy(BitConverter.GetBytes(record.Port), 0,
returnValue, 5, 2);
return returnValue;
}
public void Pack()
{
long freeBytes = 0;
byte[] buffer = new byte[RecordSize];
Queue<long> deletes = new Queue<long>();
file.Seek(0, SeekOrigin.Begin);
while (file.Position < file.Length)
{
long offset = file.Position;
file.Read(buffer, 0, RecordSize);
if (buffer[0] == Deleted[0])
{
deletes.Enqueue(offset);
freeBytes += RecordSize;
}
else
{
if (deletes.Count > 0)
{
deletes.Enqueue(offset);
file.Seek(deletes.Dequeue(), SeekOrigin.Begin);
file.Write(buffer, 0, RecordSize);
file.Seek(offset + RecordSize, SeekOrigin.Begin);
}
}
}
file.SetLength(file.Length - freeBytes);
}
public void Sort()
{
int offset = -RecordSize; // lazy method
List<Record> records = this.Locate(r => true).ToList();
records.Sort(new RecordComparer());
foreach (Record record in records)
{
record.Offset = offset += RecordSize;
Update(record);
}
}
public void Dispose()
{
if (file != null)
file.Close();
}
}
以下に、実際の例を示します。
static void Main(string[] args)
{
List<IPEndPoint> endPoints = new List<IPEndPoint>(
new IPEndPoint[]{
new IPEndPoint(IPAddress.Parse("127.0.0.1"), 80),
new IPEndPoint(IPAddress.Parse("69.59.196.211"), 80),
new IPEndPoint(IPAddress.Parse("74.125.45.100"), 80)
});
using (DatabaseFile dbf = new DatabaseFile("iptable.txt"))
{
foreach (IPEndPoint endPoint in endPoints)
dbf.Append(new Record {
Address = endPoint.Address,
Port = endPoint.Port });
Record stackOverflow = dbf.Locate(r =>
Dns.GetHostEntry(r.Address)
.HostName.Equals("stackoverflow.com")).FirstOrDefault();
if (stackOverflow != null)
dbf.Delete(stackOverflow);
Record google = dbf.Locate(r =>
r.Address.ToString() == "74.125.45.100").First();
google.Port = 443;
dbf.Update(google);
foreach(Record http in dbf.Locate(r =>
!r.Deleted && r.Port == 80))
Console.WriteLine(http.ToString());
}
Console.ReadLine();
}
dBase III、あなたがいなくて寂しいです。
楽しかったです、ありがとう!
編集1:追加さPack()
れた怠惰なSort()
コード。
編集2IComparable/IComparer
:不足している実装を追加
私は個人的に行きます
192.100.10.1:500:20-21
192.100.10.2:27015-27016:80
最初がIPで、その後のすべて:
がポートである場合、範囲を表すこともでき-
ます。非常に夢中になりたい場合はu
、ポートタイプを表すaを導入できUDP
ますTCP
。たとえば、次のようになります。
192.100.10.2:27015-27016:80:90u
そしてexplode()
、上記のために非常に簡単に動作します。
挿入削除と更新について話すとき..次のようなクラス構造を簡単に作成できます
struct port{
int portnum;
char type;
port(int portnum = 0, char type = 't'){
this.portnum = portnum; this.type = type;
}
}
class Ip{
public:
string Ip_str;
list <port> prt;
}
そして、あなたはメインを次のように見せることができます
int main(){
list<Ip> Ips;
//Read the list from file and update the list.
//Sort delete update the list
//Rewrite the list back into file in the order mentioned obove
return 0;
}
.NET BCLは、最初にファイルをメモリにロードせずにファイルに対してクエリを実行し、追加/削除をサポートするため、探しているものを提供しません。したがって、独自の組み込みデータベースをロールする必要があるか、SQLitehttp://www.sqlite.org/のようなものを使用することができます。
IPとポートは1対多の関係です。私はこのようなことを考えます
\ t192.168.1.1 \ r \ n25 \ r \ n26 \ r \ n \ t192.168.1.2 \ r \ n2 \ r \ n80 \ r \ n110
ここで、\ tはタブ、\ r\nはキャリッジリターンとそれに続く改行です。
したがって、解析するときにタブ文字を押すと、そこから改行までのすべての行がIPアドレスであることがわかり、タブを押すまで、次の改行の間のすべてがそのIPアドレスのポート番号になります。この場合、新しいIPアドレスを使用しています。これは単純で高速ですが、人間が読める形式ではありません。
最も簡単な方法は、IPとポートを含む小さなクラスを作成することです。
class IpAddress
{
public string IP;
public int port;
}
次に、それらを作成しlist<IpAddress>
ます。次に、XMLシリアル化と逆シリアル化を使用して、リストのファイルの読み取りと書き込みを行うことができます。
これはIPやポートとは何の関係もありません。問題は、私が知る限り、Windowsがファイルの途中でバイトを挿入または削除できないことです。