Frage

Ich suche ein Gutes und schnell Möglichkeit zum Verwalten von IP -Adressen und -Ports in einer Datei. Eine Art DB -Tabelle mit 2 Spalten: IP und Port, jedoch in einer Datei ohne Verwendung eines DB.

Es muss das Hinzufügen, Löschen und Aktualisieren unterstützen. Es ist mir egal, dass es von Parallelität ist.

War es hilfreich?

Lösung

Im Folgenden kommen einige, um Ihre Aufgabe zu erledigen. Ich habe versucht, streng auf den Punkt zu gehen, also fehlt vielleicht etwas.

Ich würde eine "Datensatz" -Klasse erstellen, um IP/Port -Paare zu halten

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);
    }
}

... und eine "Datenbankdatei" -Klasse zur Verwaltung von Datendatei -Interaktion.

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();
    }
}

Unten ein funktionierendes Beispiel:

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, ich vermisse dich.

Nun, das hat Spaß gemacht, danke!

Bearbeiten 1: Hinzugefügt Pack() und faul Sort() Code;

Bearbeiten 2: Fehlende hinzugefügt IComparable/IComparer Implementierung

Andere Tipps

Ich persönlich werde mich entscheiden

192.100.10.1:500:20-21

192.100.10.2:27015-27016:80

Wo die erste die IP und alles nach dem ist : ist ein Port, wir können auch einen Bereich von darstellen - Und wenn wir sehr verrückt danach sein wollen, können wir eine vorstellen u die den Port -Typ darstellen UDP oder TCP zum Beispiel:

192.100.10.2:27015-27016:80:90u

Und explode() Würde für die oben genannten ganz leicht funktionieren.

Wenn wir über das Einfügen von Löschen und Aktualisierungen sprechen, können wir einfach eine Klassenstruktur erstellen, z.

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;
}

Und dann können Sie das Haupt haben, wie Sie aussehen können

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;
}

Der einfachste Weg ist wahrscheinlich, eine kleine Klasse zu erstellen, die Ihre IP und Ihren Port enthält

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

und dann eine erstellen a list<IpAddress> von ihnen. Sie können dann die XML -Serialisierung und -Deserialisierung verwenden, um eine Datei Ihre Liste zu lesen und aus zu schreiben.

Die .NET BCL bietet nicht das an, wonach Sie suchen, wenn Sie an einer Datei abfragen möchten, ohne sie zuerst in den Speicher zu laden und hinzufügen/entfernen. Sie müssten also entweder Ihre eigene eingebettete Datenbank rollen oder Sie könnten einfach so etwas wie SQLite verwenden http://www.sqlite.org/

IP und Port sind ein einzelnes zu vielen Beziehung. Ich würde so etwas in Betracht ziehen

t192.168.1.1 r n25 r n26 r n t192.168.1.2 r n2 r n80 r n110

wobei t ein Tab ist und r n eine Wagenrendite gefolgt von einer neuen Linie

Wenn Sie also analysieren, wenn Sie auf einen Registerkartencharakter klicken, wissen Sie, dass alles, was in dieser Zeile von dort zur Newline ist, eine IP -Adresse ist, dann ist alles zwischen den nächsten Newlines eine Portnummer für diese IP -Adresse, bis Sie auf eine Registerkarte klicken. In diesem Fall befinden sich eine neue IP -Adresse. Das ist einfach und schnell, aber nicht als menschlich lesbar.

Dies hat nichts mit IP und Ports zu tun. Das Problem ist, dass Windows, soweit ich weiß, nicht erlaubt, Bytes in/aus der Mitte einer Datei einzufügen oder zu entfernen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top