Идеи для управления IP и портами в формате ключ / значение? - PullRequest
0 голосов
/ 10 октября 2009

Я ищу хороший и быстрый способ управления IP-адресами и портами в файле. Сортировка таблицы БД, которая имеет 2 столбца: IP и порт, но в файле, без использования БД.

Он должен поддерживать добавление, удаление и обновление. Меня не волнует параллелизм.

Ответы [ 6 ]

2 голосов
/ 10 октября 2009

Ниже некоторые приходят, чтобы выполнить вашу задачу. Я пытался перейти строго к делу, поэтому, возможно, чего-то не хватает.

Я бы создал класс "Запись", чтобы сохранить пары ip / port

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() код;

РЕДАКТИРОВАТЬ 2 : добавлена ​​пропущенная IComparable/IComparer реализация

1 голос
/ 10 октября 2009

лично я пойду за

192.100.10.1:500:20-21

192.100.10.2:27015-27016:80

Если первым является Ip, а каждая вещь после : является портом, мы также можем представить диапазон с помощью -, и если мы хотим быть очень безумными, мы можем ввести u, который будет представляет тип порта 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;
}
0 голосов
/ 10 октября 2009

это не имеет ничего общего с IP и портами .. проблема в том, что, насколько я знаю, windows не позволяет вставлять или удалять байты в / из середины файла ..

0 голосов
/ 10 октября 2009

IP и порт - это отношения один ко многим. Я хотел бы рассмотреть что-то вроде этого

\ t192.168.1.1 \ г \ n25 \ г \ n26 \ г \ п \ t192.168.1.2 \ г \ п2 \ г \ n80 \ г \ N110

где \ t - это табуляция, а \ r \ n - возврат каретки, за которым следует новая строка

Таким образом, когда вы анализируете, если вы нажимаете символ табуляции, вы знаете, что все, что находится в этой строке оттуда до новой строки, является IP-адресом, тогда все, что находится между следующими символами новой строки, является номером порта для этого IP-адреса, пока вы не нажмете вкладка, в этом случае вы находитесь на новый IP-адрес. Это просто и быстро, но не так, чтобы читалось человеком.

0 голосов
/ 10 октября 2009

.NET BCL не предлагает то, что вы ищете, так как вы хотите выполнить запрос к файлу без предварительной загрузки его в память и поддержки добавления / удаления. Так что вам придется либо свернуть собственную встроенную базу данных, либо просто использовать что-то вроде SQLite http://www.sqlite.org/

0 голосов
/ 10 октября 2009

Самый простой способ - создать небольшой класс, содержащий ваш IP и порт

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

, а затем создайте list<IpAddress> из них. Затем вы можете использовать сериализацию и десериализацию XML для чтения и записи в файл вашего списка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...