أفكار لإدارة IP والمنافذ بتنسيق المفتاح/القيمة؟
سؤال
أنا أبحث عن جيد و سريع طريقة لإدارة عناوين IP والمنافذ في ملف. نوع من جدول DB الذي يحتوي على عمودين: IP والمنفذ ، ولكن في ملف ، دون استخدام DB.
يجب أن تدعم إضافة وحذف وتحديث. لا يهمني من التزامن.
المحلول
أدناه ، يأتي البعض لإكمال مهمتك. حاولت الذهاب بدقة إلى هذه النقطة ، لذلك ربما يكون هناك شيء مفقود.
سأقوم بإنشاء فئة "سجل" ، للحفاظ على أزواج IP/المنفذ
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" لإدارة تفاعل DataFile.
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
تطبيق
نصائح أخرى
أنا شخصيا سأذهب ل
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;
}
من المحتمل أن تكون أسهل طريقة هي إنشاء فئة صغيرة تحتوي على IP ومنفذك
class IpAddress
{
public string IP;
public int port;
}
ثم إنشاء ملف list<IpAddress>
منهم. يمكنك بعد ذلك استخدام تسلسل XML و Deserialization للقراءة والكتابة من ملفك.
لا يقدم .NET BCL ما تبحث عنه كما تريد الاستعلام عن ملف دون تحميله في الذاكرة أولاً ودعم الإضافة/إزالة. لذلك يجب عليك إما لفة قاعدة البيانات المدمجة الخاصة بك أو يمكنك ببساطة استخدام شيء مثل SQLite http://www.sqlite.org/
IP والمنفذ هو واحد للعديد من العلاقة. سأعتبر شيئًا كهذا
t192.168.1.1 r n25 r n26 r n t192.168.1.2 r n2 r n80 r n110
حيث t عبارة
لذلك عندما تقوم بتحليل ، إذا قمت بالضغط على حرف TAB ، فأنت تعرف أن كل شيء موجود في هذا السطر من هناك إلى خط جديد هو عنوان IP ، فإن كل شيء بين الخطوط الجديدة التالية هو رقم منفذ لعنوان IP هذا حتى تضغط على علامة التبويب ، في هذه الحالة ، تكون على عنوان IP جديد. هذا بسيط وسريع ولكن ليس قابلاً للقراءة البشرية.
هذا لا علاقة له بـ IP والمنافذ .. المشكلة هي أنه ، على حد علمي ، لا تسمح Windows بإدخال أو إزالة البايتات في/من منتصف الملف ..