![]() |
Delphi-Version: XE
MAC-Hersteller-Zuordnung bzw. Wie mit einem sehr großen Datensatz umgehen?
Liste der Anhänge anzeigen (Anzahl: 1)
Ich möchte in einem Programm gerne den zu einer MAC-Adresse zugehörigen Hersteller anzeigen. Dieser lässt sich ja an den ersten drei Bytes erkennen, da diese offiziell vergeben werden. Nun steht da sonst nicht so viel Logik dahinter und die Zuordnung wird in langen Listen öffentlich dokumentiert. Diese lassen sich in unterschiedlichen Formen beispielsweise hier abrufen:
![]() Ich habe die Datei mit den Kurzformen hier zusätzlich angehängt, da der Download von deren Server immens langsam ist. So eine Auflistung hat über 23.000 Einträge. Mein Problem ist nun, dass ich überhaupt keine Idee habe, wie ich damit in Delphi am besten umgehen sollte. Folgende Kriterien hätte ich damit gerne erfüllt:
|
AW: MAC-Hersteller-Zuordnung bzw. Wie mit einem sehr großen Datensatz umgehen?
Zu 1.: Als Textdatei als Ressource einkompilieren und zur Abfrage temporär entpacken.
Da es wohl kein System gi9bt,bleibt wohl nur eine lange Case-Abfrage übrig. |
AW: MAC-Hersteller-Zuordnung bzw. Wie mit einem sehr großen Datensatz umgehen?
Hab mal einbisserl rumgespielt, dabei ist das rausgekommen:
Delphi-Quellcode:
zu benutzen in z. B. der Form:
unit nmap_mac_prefixes;
interface uses Classes; type tNMap_Mac_List = class(TObject) fHex : TStringList; fName : TStringList; private procedure Init000; procedure Init001; procedure Init002; procedure Init003; procedure Init004; procedure Init005; procedure Init006; procedure Init007; procedure Init008; procedure Init009; procedure Init010; procedure Init011; procedure Init012; procedure Init013; procedure Init014; procedure Init015; procedure Init016; procedure Init017; procedure Init018; procedure Init019; procedure Init020; procedure Init021; procedure Init022; procedure Init023; procedure Init024; procedure Init025; procedure Init026; procedure Init027; procedure Init028; procedure Init029; procedure Init030; procedure Init031; procedure Init032; procedure Init033; procedure Init034; procedure Init035; procedure Init036; procedure Init037; procedure Init038; procedure Init039; procedure Init040; procedure Init041; procedure Init042; procedure Init043; procedure Init044; procedure Init045; procedure Init046; public constructor Create; destructor Destroy; override; function GetName(AHex : String) : String; end; implementation constructor tNMap_Mac_List.Create; begin fHex := TStringList.Create; fName := TStringList.Create; Init000; Init001; Init002; Init003; Init004; Init005; Init006; Init007; Init008; Init009; Init010; Init011; Init012; Init013; Init014; Init015; Init016; Init017; Init018; Init019; Init020; Init021; Init022; Init023; Init024; Init025; Init026; Init027; Init028; Init029; Init030; Init031; Init032; Init033; Init034; Init035; Init036; Init037; Init038; Init039; Init040; Init041; Init042; Init043; Init044; Init045; Init046; end; destructor tNMap_Mac_List.Destroy; begin fName.Free; fHex.Free; end; function tNMap_Mac_List.GetName(AHex : String) : String; var iIndex : Integer; begin iIndex := fHex.IndexOf(AHex); if iIndex > -1 then Result := fName[iIndex] else Result := '<unbekannt>'; end; procedure tNMap_Mac_List.Init000; begin fHex.Add('000000'); fName.Add('Xerox'); fHex.Add('000001'); fName.Add('Xerox'); fHex.Add('000002'); fName.Add('Xerox'); fHex.Add('000003'); fName.Add('Xerox'); fHex.Add('000004'); fName.Add('Xerox'); fHex.Add('000005'); fName.Add('Xerox'); fHex.Add('000006'); fName.Add('Xerox'); fHex.Add('000007'); fName.Add('Xerox'); fHex.Add('000008'); fName.Add('Xerox'); fHex.Add('000009'); fName.Add('Xerox'); fHex.Add('00000A'); fName.Add('Omron Tateisi'); ... und viele weitere Zeilen dieser Art ... ... verteilt auf 46 Prozeduren, da ansonsten zuviele Konstanten in einer Prozedur enthalten sind ... ... vollständig im Anhang ... fHex.Add('FCF8B7'); fName.Add('TRONTEQ'); fHex.Add('FCFAF7'); fName.Add('Shanghai Baud Data'); fHex.Add('FCFBFB'); fName.Add('Cisco'); fHex.Add('FCFC48'); fName.Add('Apple'); fHex.Add('FCFE77'); fName.Add('Hitachi Reftechno'); fHex.Add('FCFEC2'); fName.Add('Invensys Controls UK'); fHex.Add('FCFFAA'); fName.Add('IEEE Registration Authority'); end; end.
Delphi-Quellcode:
Ob das jetzt unbedingt eine sinnvolle Lösung ist, weiß ich nicht, aber es läßt sich kompilieren und ist damit alles in der EXE drin ;-)
var
procedure Irgendwas(AMac : String); x : tNMap_Mac_List; begin x := tNMap_Mac_List.Create; ShowMessage(x.GetName(AMac)); x.Free; end; |
AW: MAC-Hersteller-Zuordnung bzw. Wie mit einem sehr großen Datensatz umgehen?
Danke für den ersten Ansatz. :)
Ich weiß nicht, ob das so geschickt ist, die Bytes als String zu verwenden. Wenn man sie als das, was sie ja eigentlich sind, nehmen würde, sollte das eigentlich performanter und vermutlich auch platzsparender sein. Auf jeden Fall aber übergeht Dein Ansatz die Anforderung, die Redundanz zu entfernen. Denn statt einer platzsparenden Zuordnung von Name zu mehreren MAC-Bytes, muss für jeden 3Byte-Eintrag ein Herstellername stehen. Klar, die könnte man auch noch mühevoll durch Konstanten ersetzen und die Konstanten referenzieren, aber dann wäre eswahrscheinlich gleich besser, das andersherum zu machen. |
AW: MAC-Hersteller-Zuordnung bzw. Wie mit einem sehr großen Datensatz umgehen?
Mann, Du bist aber anspruchsvoll ;-)
Ok: Luckies Caseansatz könnte dann so aussehen:
Delphi-Quellcode:
Das ist allerdings nicht kompilierbar, wegen doppelter Case-Label. So ist z. B. 080030 nicht eindeutig, sondern wird von drei Firmen genutzt: Cern, Network und Royal Melbourne Inst Of. Da wirst Du Dir dann wohl noch eine andere Lösung suchen müssen :-(
unit nmap_mac_prefixes;
interface function GetMac(AMac : Integer) : String; implementation function GetMac(AMac : Integer) : String; begin case AMac of $30F33A: Result := '+plugg srl'; $700258: Result := '01DB-Metravib'; $C49313: Result := '100fio networks'; $080024: Result := '10NET/DCA'; $000B10: Result := '11wave Technonlogy'; $A85EE4: Result := '12Sided'; $005029: Result := '1394 Printer Working Group'; $00A02D: Result := '1394 Trade Association'; $001974: Result := '16063'; $003070: Result := '1Net'; $54369B: Result := '1Verge Internet'; $443719: Result := '2 Save Energy'; $0011B2: Result := '2001'; $0025C3: Result := '21168'; $EC9681: Result := '2276427 Ontario'; $001387: Result := '27M'; $000761: Result := '29530'; $28F358: Result := '2C - Trifonov'; $3C3F51: Result := '2CRSI'; $0016A9: Result := '2EI'; $B8B7D7: Result := '2GIG'; $001B8A: Result := '2M'; $001929: Result := '2M2B Montadora de Maquinas Bahia Brasil'; $7C1EB3: Result := '2N TELEKOMUNIKACE a.s'; $F82C18, $28162E, $383BC8, $94C150, $001288, $002456, $60FE20, $982CBE, $0022A4, $002650, $34EF44, $00183F, $002351, $00D09E, $001FB3, $DC7FA4, $749DDC, $00253C, $0019E4, $001EC7, $F81897, $640F28, $C0830A, $000D72, $3CEA4F, $00217C, $60C397, $001D5A, $B8E625, $B0E754, $14EDBB, $001AC4, $001B5B, $001495: Result := '2Wire'; ... und viele weitere Zeilen ... ... vollständig im Anhang ... $000689: Result := 'yLez'; $8CC7D0: Result := 'zhejiang ebang'; $30F31D, $28FF3E, $78312B, $DC028E, $4C09B4, $601466, $84742A, $E47723, $30D386, $2C26C5, $601888, $B805AB, $8C7967, $A8A668, $744AA4, $901D27, $F4B8A7, $C864C7, $4C16F1, $688AF0, $709F2D, $789682, $4CAC0A, $D0154A, $4CCBF5, $48282F, $FCC897, $B4B362, $CC1AFA, $540955, $300C23, $48A74E, $B49842, $346987, $004A77, $344DEA, $F41F88, $343759, $344B50, $F084C9, $001E73, $88D274, $B075D5, $986CF5, $C87B5B, $F46DE2, $702E22, $AC6462, $981333, $CC7B35, $2C957F, $C4A366, $681AB2, $34DE34, $D855A3, $A0EC80, $208986, $D437D7, $64136C, $FC2D5E, $0C1262, $083FBC, $94A7B7, $EC1D7F, $002293, $D87495, $38D82F, $749781, $08181A, $D476EA, $1844E6, $9CA9E4, $146080, $F8DFA8, $9CD24B, $18686A, $002512, $D4C1C8, $E07C13, $F8A34F, $A091C8, $10D0AB, $143EBF, $3CDA2A, $0015EB, $74A78E, $98F537, $98F428, $8CE081, $78C1A7, $5422F8, $54BE53, $6C8B2F, $8CE117, $0026ED, $44F436, $6CA75F, $EC237B, $F4E4AD, $34E0CF, $0019C6, $EC8A4C, $384608, $6073BC, $D071C4, $90C7D8, $90D8F3, $E0C3F3, $78E8B6, $74B57E, $D0608C, $D05BA8, $D058A8, $24C44A, $689FF0, $A47E39, $049573: Result := 'zte'; else Result := '<unbekannt>'; end; end; end. Allerdings halten sich die Dubletten im Rahmen, folgende hab' ich finden können:
Code:
Dafür wäre der Aufruf aber deutlich einfacher:
0001C8 Conrad und Thomas Conrad
080030 Cern, Network und Royal Melbourne Inst Of
Delphi-Quellcode:
ShowMessage(GetMac($000019));
|
AW: MAC-Hersteller-Zuordnung bzw. Wie mit einem sehr großen Datensatz umgehen?
Oh wow, ja das ist super!
Irgendwie habe ich mich gedanklich in andere Richtungen verrannt. DANKE!! Die Dubletten sind nicht schlimm. Die werden dann eben zusammengefasst. Kann ja nichts dafür, dass die so vergeben wurden. :) Hast Du Dir da extra einen Parser dafür geschrieben? |
AW: MAC-Hersteller-Zuordnung bzw. Wie mit einem sehr großen Datensatz umgehen?
Parser wäre da wohl deutlich übertrieben ;-)
Mein Editor unterstützt die Nutzung von Pascal-Script. Und dafür hab' ich mir halt folgenden Quelltext zusammengedaddelt:
Delphi-Quellcode:
GetSelText holt den im Editor markierten Text, SelText ist 'ne Stringliste mit eben diesem Text und WriteLn schreibt in ein Ausgabefenster (ein TMemo).
program Test;
var i : Integer; k : Integer; s : String; sCase : String; procedure Dubletten; begin GetSelText; s := ''; for i := 0 to SelText.Count - 1 do begin if s = Copy(SelText[i],1,6) then begin WriteLn(Format('Dublette %s',[Copy(SelText[i],1,6)])); WriteLn(Format('Dublette %s',[Copy(SelText[i - 1],8,4096)])); WriteLn(Format('Dublette %s',[Copy(SelText[i],8,4096)])); end; s := Copy(SelText[i],1,6); end; end; procedure CaseErstellen; begin GetSelText; k := 0; s := AnsiReplaceText(Copy(SelText[0],8,4096),'''',''''' '); s := ''; sCase := ''; for i := 0 to SelText.Count - 1 do begin if s <> AnsiReplaceText(Copy(SelText[i],8,4096),'''',''''' ') then begin WriteLn(Format(' %s: Result := ''%s'';',[sCase,s])); s := AnsiReplaceText(Copy(SelText[i],8,4096),'''',''''' '); sCase := '$' + Copy(SelText[i],1,6); end else begin if Length(sCase) = 70 then begin WriteLn(Format(' %s,',[sCase])); sCase := ''; end; if sCase = '' then sCase := '$' + Copy(SelText[i],1,6) else sCase := sCase + ', $' + Copy(SelText[i],1,6); end; end; WriteLn(Format(' %s: Result := ''%s'';',[sCase,s])); end; procedure InitErstellen; begin GetSelText; k := 0; for i := 0 to SelText.Count - 1 do begin if (i mod 500 = 0) then begin if i > 0 then begin WriteLn('end;'); WriteLn(''); end; Output.Add(Format(' procedure Init%0.3d;',[k])); WriteLn(Format('procedure tNMap_Mac_List.Init%0.3d;',[k])); WriteLn('begin'); k := k + 1; end; WriteLn(Format(' fHex.Add(''%s''); fName.Add(''%s'');',[Copy(SelText[i],1,6),AnsiReplaceText(Copy(SelText[i],8,4096),'''',''''' ')])); end; WriteLn('end;'); end; begin // InitErstellen; // CaseErstellen; Dubletten; end. Der Rest ist "handelsübliches" Delphi und einbisserl Schreibarbeit ;-) Wenn Du das auf Delphi umbauen möchtest, musst Du halt noch zwei Stringlisten machen.
Delphi-Quellcode:
Und damit dürfte es mit marginaler Nacharbeit möglich sein, ggfls. aus 'ner neuen nmap-mac-prefixes.txt den Case-Teil zu generieren.
SelText := TStringList.Create;
Ausgabe := TStringList.Create; SelText.LoadFromFile('nmap-mac-prefixes.txt'); // Statt WriteLn(...); halt Ausgabe.Add(...); Ausgabe.SaveToFile('nmap_mac_prefixes.inc'); Ausgabe.Free; SelText.Free; Für die Dublettenprüfung muss die Datei nmap-mac-prefixes.txt ab der 1. Spalte sortiert sein, für das Erstellen des Case-Teiles und die erste Stringlistenvariante ab der 8. Spalte. |
AW: MAC-Hersteller-Zuordnung bzw. Wie mit einem sehr großen Datensatz umgehen?
Das ist doch eine typische Datenbankanwendung.
Die Daten normalisieren, sprich zwei Tabellen erstellen und dann mit binärer Suche dadurch hüpfen. Gruß K-H |
AW: MAC-Hersteller-Zuordnung bzw. Wie mit einem sehr großen Datensatz umgehen?
Liste der Anhänge anzeigen (Anzahl: 2)
Moin...:P
Wenn es keine DB hat, dann würde ich die Textdatei als Ressource kompilieren. Nach dem Programmstart würde ich die Ressource einlesen. Für die Lagerung der Informationen käme ein TDictionary<string, string> in Frage. Beim Einlesen wird aus jeder Zeile aus den ersten 6 Zeichen der Key generiert in der Rest ist das Value. Die Dupletten kannst du schon beim Einlesen handeln. Wenn der Key existiert dann den Value an den bestehenden Value hängen. ...fertsch. :zwinker: Vorteil: 1. Liste.LoadFromFile('nmap-mac-prefixes.txt'); ist nicht notwendig da die Textdatei zur Laufzeit nicht beigelegt werden muß...wird beim Erzeugen einkompiliert. 2. Keine Änderung des Quelltextes bei Inhaltsänderungen der TXT...einfach neu kompilieren. :thumb: 3. Ein Dictionary ist dafür da was aus einer "Liste" herauszusuchen...deutlich schneller als TStringlist. :zwinker:
Delphi-Quellcode:
RC Datei Inhalt:
unit Unit1;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, System.Generics.Collections, System.Generics.Defaults, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private FDictionary: TDictionary<string, string>; procedure ReadFile; public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject); begin FDictionary := TDictionary<string, string>.Create; ReadFile; end; procedure TForm1.FormDestroy(Sender: TObject); begin FDictionary.Free; end; procedure TForm1.ReadFile; var I: Integer; Content: TStringList; TextStream: TResourceStream; CurrentRowKey: string; CurrentRowValue: string; begin FDictionary.Clear; Content := TStringList.Create; try TextStream := TResourceStream.Create(HInstance, 'Content', PWideChar('ContentFile')); try Content.LoadFromStream(TextStream); for I := 0 to Content.Count - 1 do begin CurrentRowKey := Copy(Content[I], 1, 6); if not FDictionary.TryGetValue(CurrentRowKey, CurrentRowValue) then begin // einfügen CurrentRowValue := Copy(Content[I], 8, Length(Content[I]) + 8); FDictionary.Add(CurrentRowKey, CurrentRowValue); end else begin // Key zusammensetzen bei Duplikaten CurrentRowValue := Copy(Content[I], 8, Length(Content[I]) + 8); FDictionary.AddOrSetValue(CurrentRowKey, FDictionary.Items[CurrentRowKey] + '; ' + CurrentRowValue); end; end; finally TextStream.Free; end; finally Content.Free; end; end; end. Zitat:
|
AW: MAC-Hersteller-Zuordnung bzw. Wie mit einem sehr großen Datensatz umgehen?
War auch meine erste Idee. Nur er will alles in einer Datei weiter geben ohne (Installation.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:30 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz