以键/值格式管理 IP 和端口的想法?

发布于 2024-08-06 19:41:09 字数 124 浏览 3 评论 0原文

我正在寻找一种良好且快速的方法来管理文件中的 IP 地址和端口。对具有 2 列的数据库表进行排序:IP 和端口,但在文件中,不使用数据库。

它必须支持添加、删除和更新。我不在乎并发性。

I'm looking for a good and fast way to manage IP addresses and ports in a file. Sort of a DB Table that has 2 columns: IP and Port, but in a file, without using a DB.

It has to support adding, deleting and updating. I don't care from concurrency.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

廻憶裏菂餘溫 2024-08-13 19:41:09

下面,有的来完成你的任务。我试图严格抓住要点,所以也许遗漏了一些东西。

我要创建一个“Record”类,以保留 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实现

Below, some come to complete your task. I tried to go strictly to the point, so maybe something is missing.

I'd to create a "Record" class, to keep ip/port pairs

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

...And a "DatabaseFile" class to manage datafile interaction.

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

Below, a working example:

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, I miss you.

Well, that was fun, thank you!

EDIT 1: Added Pack() and lazy Sort() code;

EDIT 2: Added missing IComparable/IComparer implementation

风追烟花雨 2024-08-13 19:41:09

我个人会选择

192.100.10.1:500:20-21

192.100.10.2:27015-27016:80

其中第一个是 Ip 以及 之后的所有内容>: 是一个端口,我们还可以用 - 表示一个范围,如果我们想对此非常疯狂,我们可以引入一个 u 来表示端口类型 UDPTCP 例如:

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

然后你可以让 main 看起来像

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

I personally will go for

192.100.10.1:500:20-21

192.100.10.2:27015-27016:80

Where the first is the Ip and every thing after the : is a port, We can also represent a range by - and if we want to be very crazy about it we can introduce a u which will represent the port type UDP or TCP for example:

192.100.10.2:27015-27016:80:90u

And explode() would work for the above quite easily.

When talking about Inserting Deleting and updating.. We can simply create a class structure such as

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

And then you can have the main to look like

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;
}
时光病人 2024-08-13 19:41:09

最简单的方法可能是创建一个包含您的 IP 和端口的小类

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

,然后创建它们的列表。然后,您可以使用 XML 序列化和反序列化来读取和写入列表文件。

The easiest way is probably to create a small class that contains your IP and port

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

and then create a list<IpAddress> of them. You can then use XML Serialization and Deserialization to read to and write from a file your list.

凉城凉梦凉人心 2024-08-13 19:41:09

.NET BCL 不提供您正在寻找的内容,因为您想要查询文件而不先将其加载到内存中并支持添加/删除。因此,您要么必须推出自己的嵌入式数据库,要么可以简单地使用 SQLite http://www.sqlite 之类的东西.org/

The .NET BCL does not offer what you are looking for as you want to query against a file without loading it into memory first and support add/remove. So you'd either have to roll your own embedded database or you could simply use something like SQLite http://www.sqlite.org/

も星光 2024-08-13 19:41:09

IP和端口是一对多的关系。我会考虑这样的

\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 and Port is a one to many relationship. I would consider something like this

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

where \t is a tab and \r\n is a carriage return followed by a newline

So when you parse, if you hit a tab character, you know everything that's in that line from there to the newline is an IP address, then everything in between the next newlines is a port number for that IP address until you hit a tab, in which case you're on a new IP address. That's simple and fast but not as human readable.

流云如水 2024-08-13 19:41:09

这与IP和端口无关。问题是,据我所知,Windows不允许在文件中间插入或删除字节。

this has nothing to do with IP and ports.. the problem is that, as far as i know, windows does not allow to INSERT or remove bytes in/from the middle of a file..

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文