0

ファイル内のIPアドレスとポートを管理するための優れた高速な方法を探しています。IPとポートの2つの列があり、DBを使用せずにファイル内にあるDBテーブルの一種。

追加、削除、更新をサポートする必要があります。並行性は気にしません。

4

6 に答える 6

2

以下に、あなたのタスクを完了するために来る人もいます。厳密に要点を絞ろうとしたので、何か足りないのかもしれません。

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 :不足している実装を追加

于 2009-10-10T14:37:06.890 に答える
1

私は個人的に行きます

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;
}
于 2009-10-10T16:20:50.083 に答える
0

.NET BCLは、最初にファイルをメモリにロードせずにファイルに対してクエリを実行し、追加/削除をサポートするため、探しているものを提供しません。したがって、独自の組み込みデータベースをロールする必要があるか、SQLitehttp://www.sqlite.org/のようなものを使用することができます

于 2009-10-10T00:25:07.263 に答える
0

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アドレスを使用しています。これは単純で高速ですが、人間が読める形式ではありません。

于 2009-10-10T00:26:19.997 に答える
0

最も簡単な方法は、IPとポートを含む小さなクラスを作成することです。

class IpAddress
{
    public string IP;
    public int port;
}

次に、それらを作成しlist<IpAddress>ます。次に、XMLシリアル化と逆シリアル化を使用して、リストのファイルの読み取りと書き込みを行うことができます。

于 2009-10-09T23:53:19.327 に答える
0

これはIPやポートとは何の関係もありません。問題は、私が知る限り、Windowsがファイルの途中でバイトを挿入または削除できないことです。

于 2009-10-10T01:09:08.083 に答える