Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   TGUID - einzigartige ID auf andere Computer Systeme ? (https://www.delphipraxis.net/213928-tguid-einzigartige-id-auf-andere-computer-systeme.html)

paule32.jk 20. Okt 2023 13:54

TGUID - einzigartige ID auf andere Computer Systeme ?
 
Hallo,

es gibt ja so ein kleines Tool, mit dem man eine TGUID erstellen kann.
Was ist aber, wenn die vom "Eigenen" System (un)abhänge GUID erzeugt, die auf einen
"Anderen" System schon erstellt und/oder reserviert wurde ?

Wird die dann in den Eigenen Applikationen wieder geändert ?

joachimd 20. Okt 2023 14:00

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
GUID = global unique identifier
die Wahrscheinlichkeit, dass zwei Systeme die gleiche GUID erzeugen ist verschwindend gering.

haentschman 20. Okt 2023 14:06

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Zitat:

es gibt ja so ein kleines Tool, mit dem man eine TGUID erstellen kann.
Delphi...:duck:

paule32.jk 20. Okt 2023 14:17

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
jo. Aber meine Bedenken sind halt "auf andere Systeme"

DeddyH 20. Okt 2023 14:19

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
https://de.wikipedia.org/wiki/Univer...que_Identifier
Zitat:

Bei der Generierung nach den Standardmethoden können UUIDs für praktische Zwecke als global eindeutig angenommen werden. Obwohl die Wahrscheinlichkeit, dass ein UUID dupliziert wird, nicht null ist, ist sie so gering, dass die Wahrscheinlichkeit für eine Kollision zumeist vernachlässigbar ist. Ein Vorteil von UUIDs ist die – im Gegensatz zu den meisten anderen Nummerierungsschemata – Unabhängigkeit von einer zentralen Registrierungsstelle oder Koordinierung zwischen den Parteien.

jaenicke 20. Okt 2023 14:38

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Zitat:

Zitat von paule32.jk (Beitrag 1528428)
Was ist aber, wenn die vom "Eigenen" System (un)abhänge GUID erzeugt, die auf einen
"Anderen" System schon erstellt und/oder reserviert wurde ?

Wird die dann in den Eigenen Applikationen wieder geändert ?

Wenn du, egal ob mit Delphi selbst per Tastenkombination (Strg + Shift + G) oder mit externen Tools, eine solche GUID erzeugst, hat das keine Auswirkungen auf andere Anwendungen. In deinen eigenen Anwendungen wird nichts geändert, wenn es die GUID schon gibt, was auch daran liegt, dass es kein Register dafür gibt. Etwaige Kollisionen bleiben daher in aller Regel unentdeckt, vor allem aufgrund der Seltenheit.

Wenn du 100%ige Sicherheit brauchst, dass deine ID global eindeutig ist, nahezu 100% also nicht reicht, dann ist eine GUID der falsche Weg.

Bernhard Geyer 20. Okt 2023 14:52

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Zitat:

Zitat von haentschman (Beitrag 1528433)
Zitat:

es gibt ja so ein kleines Tool, mit dem man eine TGUID erstellen kann.
Delphi...:duck:

Code:
powershell [guid]::NewGuid()

Gausi 20. Okt 2023 14:53

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Zitat:

Zitat von jaenicke (Beitrag 1528445)
Etwaige Kollisionen bleiben daher in aller Regel unentdeckt, vor allem aufgrund der Seltenheit.

Wenn man sich die Werte auf Wikipedia so ansieht, frage ich mich, ob es überhaupt schonmal eine Kollision in diesem Kontext gegeben hat.

Zitat:

Zitat von jaenicke (Beitrag 1528445)
Wenn du 100%ige Sicherheit brauchst, dass deine ID global eindeutig ist, nahezu 100% also nicht reicht, dann ist eine GUID der falsche Weg.

Oder man wählt die "alten" Versionen der GUID-Generierung, bei denen die MAC-Adresse (des Erstellers) mit einfließt. Und wechselt ggf. generell das Format, damit man nicht zufällig eine zufällig generierte GUID damit trifft. Was natürlich immer noch nicht 100%ig ausschließt, dass sich ein anderer Entwickler genau die gleiche GUID "ausdenkt". :stupid:

Kollision bei GUIDs dürften ungefähr so wahrscheinlich sein wie "Als ich meinen 10-Millionen-Gewinn im Lotto einlösen wollte, wurde ich vom Blitz getroffen, und der Beleg ist vollständig verbrannt."

Rollo62 20. Okt 2023 15:04

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
https://en.wikipedia.org/wiki/Univer...ier#Collisions

Zitat:

... the number of random version-4 UUIDs which need to be generated in order to have a 50% probability of at least one collision is 2.71 quintillion ...

This number is equivalent to generating 1 billion UUIDs per second for about 86 years.

himitsu 20. Okt 2023 15:08

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Zitat:

Zitat von jaenicke (Beitrag 1528445)
dann ist eine GUID der falsche Weg.

Geht schon, aber er bräuchte eine zentrale Stelle, welche entweder die ID's generiert, oder zumindestens alle kennt und Doppelte abweist.

paule32.jk 20. Okt 2023 15:50

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
wir hatten doch mal so ein kleines Thema mit der Reg.DB bei Mathias...

jaenicke 20. Okt 2023 16:06

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Zitat:

Zitat von Gausi (Beitrag 1528450)
Kollision bei GUIDs dürften ungefähr so wahrscheinlich sein wie "Als ich meinen 10-Millionen-Gewinn im Lotto einlösen wollte, wurde ich vom Blitz getroffen, und der Beleg ist vollständig verbrannt."

Richtig, die Wahrscheinlichkeit ist verschwindend gering, aber nicht genau 0. Mir fällt auch kein einziger Anwqendungsfall ein, bei dem man das braucht, aber wenn er es wirklich braucht...

dummzeuch 20. Okt 2023 16:15

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
War da bei von Windows generierten GUID nicht was mit der MAC-Adresse (einer) der Netzwerkkarten? Ich meine mich dunkel zu erinnern, dass die von Windows mit verwendet wird. Kann aber sein, dass das völliger Unsinn oder veraltet ist.

paule32.jk 20. Okt 2023 16:16

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
es ging mir folgendes durch den Kopf:

- viele spielen doch mit ihren Daten und Programmen, und versehen dann Adressen oder
Offsets gerne mit:
Code:
$cafebabe oder:
$cafe     oder:
$babe     oder:
$affe

Rolf Frei 21. Okt 2023 11:42

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Unter Windows ist die erzeugte GUID unter anderem auf der MAC-Adrese basierend und somit weltweit eindeutig. Du kannst niemals 2x die gleiche GUID bekommen.

paule32.jk 21. Okt 2023 11:49

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
du weißt aber schon, das man die MAC ändern kann ?

peterbelow 21. Okt 2023 16:16

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Zitat:

Zitat von paule32.jk (Beitrag 1528489)
du weißt aber schon, das man die MAC ändern kann ?

Und? Das ist sowohl für bereits generierte als auch für neu generierte UIDs völlig irrelevant da die MAC-Adresse nicht das einzige ist, was in die Generierung einfließt.

stahli 27. Okt 2023 12:17

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Ich habe mir für den Zweck eine eigene Guid aufgebaut.
Wichtig ist mir, dass diese global persistent eindeutig sind und dass die Reihenfolge (jedenfalls auf einem Rechner) aufsteigend nachvollziehbar ist.

Sie besteht aus zwei Zeitstempeln und einem fortlaufenden Zähler.
Der erste Zeitstempel enthält den Moment des Projektstarts (ist also so eine Art Session-ID), der zweite den Moment der ID-Erzeugung.
Der Zähler läuft bei jeder ID-Erzeugung weiter zwischen 0 bis 65535. So ist die Reihenfolge gut nachvollziehbar und es gibt noch eine Differenzierung falls doch mal beide Zeitstempel auf zwei Geräten gleich sein sollten.

Ich bin nicht auf die Standard-Guid angewiesen und so ist das für mich sinnvoller und nachvollziehbarer.
Sie braucht mit 18 Byte zwei Byte mehr als die Standard-Guid.

Delphi-Quellcode:
unit myGuid;

interface

  uses

    System.Classes;

  const

    MaxWord = 65535;

  type

    PmyGuid = ^TmyGuid;

    TmyGuid = record //: 18 Byte / 144 Bit
      C : Word;     //: 2 Byte / 16 Bit
      TS1: TDateTime; //: 8 Byte / 64 Bit
      Ts2: TDateTime; //: 8 Byte / 64 Bit
      class function Create(const aGuid: PmyGuid): TmyGuid; overload; static;
      class function Create(const aGuid: String): TmyGuid; overload; static;
      class function Create(const aGuid: TmyGuid): TmyGuid; overload; static;
      class function CreateEmpty: TmyGuid; static;
      class function CreateNew: TmyGuid; static;
      class function StringIsValidGuid(const aGuid: String): Boolean; static;
      class operator Equal(const Left, Right: TmyGuid): Boolean;
      class operator NotEqual(const Left, Right: TmyGuid): Boolean; inline;
      function      GetHashCode: Integer;
      function      IsEmpty: Boolean;
      function      ToString: String;
      procedure     DoEmpty;
      procedure     DoNew;
      procedure     FromString(const aGuid: String);
      procedure     ReadFromStream(const aStream: TMemoryStream);
      procedure     WriteToStream(const aStream: TMemoryStream);
    end;

implementation

  uses

    System.SysUtils, System.DateUtils, System.Hash;

  var

    customTS1: TDateTime = 0;
    customTS2: TDateTime = 0;
    customC : Word     = 0;

  {: *********************************** TmyGuid ********************************** :}

  {: ----------------------------------- default ---------------------------------- :}

  //: 2023-10-27
  class function TmyGuid.Create(const aGuid: String): TmyGuid;
  begin
    Result := TmyGuid.CreateEmpty;
    Result.FromString(aGuid);
  end;

  //: 2023-10-27
  class function TmyGuid.Create(const aGuid: TmyGuid): TmyGuid;
  begin
    Result := aGuid;
  end;

  //: 2023-10-27
  class function TmyGuid.Create(const aGuid: PmyGuid): TmyGuid;
  begin
    Result := aGuid^;
  end;

  //: 2023-10-27
  class function TmyGuid.CreateEmpty: TmyGuid;
  begin
    Result.TS1 := 0;
    Result.TS2 := 0;
    Result.C  := 0;
  end;

  //: 2023-10-27
  class function TmyGuid.CreateNew: TmyGuid;
  begin
    customTS2 := Now;
    if (customC = MaxWord) then
      customC := 0
    else
      Inc(customC);
    Result.TS1 := customTS1;
    Result.TS2 := customTS2;
    Result.C  := customC;
  end;

  //: 2023-10-27
  class function TmyGuid.StringIsValidGuid(const aGuid: String): Boolean;
  var
    I: Integer;
    C: Char;
  begin
    if (Length(aGuid) = 42) then
      begin
        Result := True;
        for I := 1 to Length(aGuid) do
          begin
            C := aGuid[I];
            case I of
              1:
                if C <> '#' then
                  begin
                    Result := False;
                    Break;
                  end;
              19, 37:
                if C <> '-' then
                  begin
                    Result := False;
                    Break;
                  end;
            else
              if not CharInSet(C, ['0'..'9']) then
                begin
                  Result := False;
                  Break;
                end;
            end;
          end;
      end
    else
      Result := False;
  end;

  //: 2023-10-27
  class operator TmyGuid.Equal(const Left, Right: TmyGuid): Boolean;
  begin
    Result := ((Left.TS1 = Right.TS1) and (Left.TS2 = Right.TS2) and (Left.C = Right.C));
  end;

  //: 2023-10-27
  class operator TmyGuid.NotEqual(const Left, Right: TmyGuid): Boolean;
  begin
    Result := ((Left.TS1 <> Right.TS1) or (Left.TS2 <> Right.TS2) or (Left.C <> Right.C));
  end;

  //: 2023-10-27
  function TmyGuid.GetHashCode: Integer;
  begin
    Result := 17;
    Result := Result * 397 + Integer(C);
    Result := Result * 397 + THashBobJenkins.GetHashValue(TS1, sizeOf(TDateTime), 5);
    Result := Result * 397 + THashBobJenkins.GetHashValue(TS2, sizeOf(TDateTime), 7);
  end;

  //: 2023-10-27
  function TmyGuid.IsEmpty: Boolean;
  begin
    Result := ((TS1 = 0) and (Ts2 = 0) and (C = 0));
  end;

  function TmyGuid.ToString: String;
  var
    S1, S2, S3: String;
  begin
    //: #yyyymmddhhnnsszzz-yyyymmddhhnnsszzz-xxxxx
    //: #12345678901234567890123456789012345678901 - > Length = 42
    if (TS1 = 0) then
      S1 := '00000000000000000'
    else
      S1 := FormatDateTime('yyyymmddhhnnsszzz', TS1);
    if (Ts2 = 0) then
      S2 := '00000000000000000'
    else
      S2 := FormatDateTime('yyyymmddhhnnsszzz', Ts2);
    if (C = 0) then
      S3 := '00000'
    else
      S3 := Format('%0.5d', [C]);
    Result := '#' + S1 + '-' + S2 + '-' + S3;
  end;

  //: 2023-10-27
  procedure TmyGuid.DoEmpty;
  begin
    TS1 := 0;
    TS2 := 0;
    C  := 0;
  end;

  //: 2023-10-27
  procedure TmyGuid.DoNew;
  var
    lGuid: TmyGuid;
  begin
    lGuid := CreateNew;
    TS1   := lGuid.TS1;
    TS2   := lGuid.TS2;
    C    := lGuid.C;
  end;

  //: 2023-10-27
  procedure TmyGuid.FromString(const aGuid: String);

    function EncodeTS(aGuid: String): TDateTime;
    var
      AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word;
    begin
      AYear       := StrToInt(Copy(aGuid, 1, 4));
      AMonth      := StrToInt(Copy(aGuid, 5, 2));
      ADay        := StrToInt(Copy(aGuid, 7, 2));
      AHour       := StrToInt(Copy(aGuid, 9, 2));
      AMinute     := StrToInt(Copy(aGuid, 11, 2));
      ASecond     := StrToInt(Copy(aGuid, 13, 2));
      AMilliSecond := StrToInt(Copy(aGuid, 15, 3));
      Result      := EncodeDateTime(AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond);
    end;

  begin
    if (StringIsValidGuid(aGuid)) then
      begin
        TS1 := EncodeTS(Copy(aGuid, 2, 17));
        Ts2 := EncodeTS(Copy(aGuid, 20, 17));
        C  := StrToInt(Copy(aGuid, 38, 5));
      end
    else
      begin
        TS1 := 0;
        Ts2 := 0;
        C  := 0;
      end;
  end;

  //: 2023-10-27
  procedure TmyGuid.ReadFromStream(const aStream: TMemoryStream);
  begin
    aStream.ReadData(C);
    aStream.ReadData(TS1);
    aStream.ReadData(Ts2);
  end;

  //: 2023-10-27
  procedure TmyGuid.WriteToStream(const aStream: TMemoryStream);
  begin
    aStream.WriteData(C);
    aStream.WriteData(TS1);
    aStream.WriteData(Ts2);
  end;

initialization

  customTS1 := Now;
  customTS2 := Now;
  customC  := MaxWord;

end.

himitsu 27. Okt 2023 12:34

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
ich bin mir fast sicher, dass die
Delphi-Quellcode:
//: 18 Byte / 144 Bit
so nicht stimmen :angle2:

stahli 27. Okt 2023 13:41

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Oh, das stimmt.

SizeOf gibt 24 Byte an, bei TGuid nur 16.

Die einzelnen Werte sind ja aber korrekt:
Delphi-Quellcode:
  TmyGUID = record
      C : Word;     //: 2 Byte
      TS1: TDateTime; //: 8 Byte
      TS2: TDateTime; //: 8 Byte
Summe=18
Delphi-Quellcode:
  TGUID = record
    D1: Cardinal; //: 4 Byte
    D2: Word; //: 2 Byte
    D3: Word; //: 2 Byte
    D4: array[0..7] of Byte; //: 8 Byte
Summe=16
Wo ist da mein Denkfehler bzw. Wissenslücke?
TGuid ist ja auch kein gepackter Record oder so?

Mir kam es bei meinen Überlegungen darauf an, ob es "verhältnismäßig" ist, eine eigene Guid zu verwenden.
Entsprechend hatte ich die einzelnen Variablen angesehen, die verwendet werden und bin auf die kaum höhere Größe gekommen.

Die reale Größe hatte ich dann gar nicht untersucht.


EDIT: Ok, mit "packed record" komme ich auf das erwartete Ergebnis.

dummzeuch 27. Okt 2023 15:35

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Zitat:

Zitat von stahli (Beitrag 1528665)
Oh, das stimmt.

SizeOf gibt 24 Byte an, bei TGuid nur 16.

Die einzelnen Werte sind ja aber korrekt:
Delphi-Quellcode:
  TmyGUID = record
      C : Word;     //: 2 Byte
      TS1: TDateTime; //: 8 Byte
      TS2: TDateTime; //: 8 Byte
Summe=18
Delphi-Quellcode:
  TGUID = record
    D1: Cardinal; //: 4 Byte
    D2: Word; //: 2 Byte
    D3: Word; //: 2 Byte
    D4: array[0..7] of Byte; //: 8 Byte
Summe=16
Wo ist da mein Denkfehler bzw. Wissenslücke?
TGuid ist ja auch kein gepackter Record oder so?

EDIT: Ok, mit "packed record" komme ich auf das erwartete Ergebnis.

Das Problem ist, dass das erste Feld in Deinem Record nur 2 Bytes groß ist. Das zweite Feld wird aber ohne Packed auf eine 8-Byte Grenze verschoben. Dadurch gibt es zwischen dem ersten und dem zweiten Feld eine Lücke von 6 Bytes. Mit Packed Record wird diese dann entfernt.

Sinspin 27. Okt 2023 16:15

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Ich würde auch auf TDateTime verzichten, das ist ein Gleitkommawert bei dem es zu unabsichtlicher Veränderung im Millisekundenbereich kommen kann.
Mikrosekunden als Int64 ab einem bestimmten Datum halte ich für deutlich einfacher zu handeln. Auch weil es ein Wert ist den Du so wie er ist vom System abfragen kannst.

UInt64 basiert, µs Qualität TimeCode via QueryPerformanCecounter oder 2*DWord, µs Qualität, FileTime format, UTC TimeStamp via GetSystemTimePreciseAsFileTime

mytbo 27. Okt 2023 16:45

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Als Ergänzung zum Post von Thomas (dummzeuch) hier der Link zur Hilfe (Record-Typen). Zur Veranschaulichung:
Delphi-Quellcode:
type
  TTestGuid = {packed} record
    c: Word;
    ts1: TDateTime;
    ts2: TDateTime;
  end;

const
  REC_SIZE = SizeOf(TTestGuid);
var
  guid: TTestGuid;
  p: array[0..REC_SIZE - 1] of Byte absolute guid;
begin
  FillChar(guid, REC_SIZE, 0);
  FillChar(guid.ts1, SizeOf(TDateTime), MaxByte);
  guid.c := MAXWORD;
  var s: String;
  for var i: Integer := Low(p) to High(p) do
    s := s + IfThen((p[i] <> 0), '#', '*');

  ShowMessage(Format('Size: %d: %s', [REC_SIZE, s])); // Size: 24: ##******########********
Bis bald...
Thomas

himitsu 27. Okt 2023 17:54

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Die Speicherausrichtung.
Nach den ersten 2 Byte, wird der nächste Typ an den nächsten geraden 8 Byte ausgerichtet, da er so groß ist.

stahli 27. Okt 2023 18:42

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Danke Euch.

@Sinspin
Eine Änderung des Zeitstempels (des Realwertes) sollte m.E. nur möglich sein, wenn man mit den Werten rechnet.

Ich
- ermittle jedoch den Wert nur einmalig,
- speichere ihn in die Variablen,
- übergebe ich an Methoden,
- schreibe in in einen Stream,
- wandle ihn in einen String um und zurück,
- und vergleiche die Werte auf Gleichheit.

Besteht auch in diesen Fällen die Gefahr einer Verfälschung?
Wenn nicht, würde ich lieber bei den Timestamps bleiben, da diese dann beim Debugging auch besser einzuordnen sind(gestern erzeugt oder letzten Monat).

Die Systemlaufzeit wäre gleich sicher aber weniger sprechend. Wenn in meinem Anwendungsfall tatsächlich die Gefahr einer Timestampverfälschung bestehen kann, dann würde ich aber tatsächlich lieber umstellen.

mytbo 27. Okt 2023 22:48

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Für alle, die es schon vermisst haben, mORMot hat dieses Angebot:
Zitat:

TSynUniqueIdentifierGenerator: thread-safe 64-bit integer unique identifier computation
- contain generation time
- they are increasing over time (so are much easier to store/shard/balance than UUID/GUID)
- each identifier would contain a 16-bit process identifier, which is supplied by the application
- identifiers may be obfuscated as hexadecimal text, using both encryption and digital signature
Hier etwas Quelltext:
Delphi-Quellcode:
uses
  mormot.core.base,
  mormot.core.unicode,
  mormot.crypt.secure;

var
  guid: Int64;
  guidStr: String;
  guidGen: TSynUniqueIdentifierGenerator;
begin
  guidGen := TSynUniqueIdentifierGenerator.Create({Identifier:}12345, {SharedObfuscationKey:}'TopSecret', 10); // create once in application
  try
    guid := guidGen.ComputeNew;
    ShowMessage(Format('Guid: %s', [guid.ToString]));

    guidStr := Utf8ToString(guidGen.ToObfuscated(guid));
    ShowMessage(Format('Guid obfuscated: %s', [guidStr]));

    var fromObfuscatedGuid: TSynUniqueIdentifier; // Int64
    if guidGen.FromObfuscated(StringToUtf8(guidStr), fromObfuscatedGuid) then
      ShowMessage(Format('Guid: %d, From obfuscated: %d', [guid, Int64(fromObfuscatedGuid)]));

    var guidBits: TSynUniqueIdentifierBits;
    guidBits.From(guid);
    ShowMessage(Format('DateTime created: %s', [DateTimeToStr(guidBits.CreateDateTime)]));

    ShowMessage(Format('JSON: %s', [Utf8ToString(guidBits.AsVariant._JSON)]));
  finally
    guidGen.Free;
  end;
Im Beispiel ist der Identifikator "12345". Es stehen 16-Bit zur Verfügung. Eine Möglichkeit wäre, jedem Kunden/Installation eine eigene zuzuweisen.

Die Ausgabe für das Beispiel ist:
Code:
Guid: 3647375681599078401
Guid obfuscated: 7dc1647a8d032aaeebe65dff209d32ff
Guid: 3647375681599078401, From obfuscated: 3647375681599078401
DateTime created: 27.10.2023 21:20:55
JSON: {"Created":"2023-10-27T21:20:55","Identifier":12345,"Counter":1,"Value":3647375681599078401,"Hex":"329E14DB981C8001"}
Bis bald...
Thomas

Stevie 28. Okt 2023 19:37

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Dieser Thread erinnert mich stark an https://xkcd.com/927/

Sinspin 30. Okt 2023 08:23

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Zitat:

Zitat von stahli (Beitrag 1528677)
Ich
- ermittle jedoch den Wert nur einmalig,
- speichere ihn in die Variablen,
- übergebe ich an Methoden,
- schreibe in in einen Stream,
- wandle ihn in einen String um und zurück,
- und vergleiche die Werte auf Gleichheit.

Besteht auch in diesen Fällen die Gefahr einer Verfälschung?

D11 System.Pas:
Delphi-Quellcode:
TDateTime = type Double;
Ein Gleitkommazahlenwert ist intern als Bruch gespeichert, um so weiter Du hinter das Komma kommst um so ungenauer wird die Zahl.
Es hängt davon ab wie Du umwandelst. Also wieviele Stellen nach dem Komma mit erfasst werden um eine ausreichend genau zu sein.
Beim zurück wandeln von String in Gleitkomma ensteht intern mit hoher Wahrscheinlichkeit eine andere Zahl / anderer Bruch, wenn Du nicht sicherstellst das Du wieder eine ausreichende Anzahl von Nachkommastellen lieferst.

Vergleichen von Gleitkommazahlen ist wie Lose ziehen. Die Operationen finden zwar mit dem Wissen statt dass Gleitkommazahlen verglichen werden, aber 100% sicher ist das nicht.
Was klappt, aber langsam ist, wäre erst in Zeit-String-Representation umwandeln.

Generell macht es wenig Sinn sich mit Gleitkommazahlen rumzuquählen wenn es nicht unbedingt sein muss.
Deswegen wird in vielen OS darauf verzichtet. Warum Delphi sich den Schuss ins Knie geleistet hat und steif daran festhält erschließt sich mir nicht.

paule32.jk 30. Okt 2023 09:15

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Hallo,

auf welcher Basis ist denn der Delphi TDateTime ?
Wenn denn dann die Unix ist - also die bei 1970 anfängt...
... dann ist bei 2038 Sense im Gelände.

Ich weiß zwar nicht, ob ich an diesen Datum noch programmiere ... aber vielleicht ist das ja was interessantes für die jüngere Generation ...

Delphi.Narium 30. Okt 2023 09:24

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Suchmaschine meiner WahlTDateTime Delphi

Delphihilfe: System.TDateTime

paule32.jk 30. Okt 2023 10:05

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Liste der Anhänge anzeigen (Anzahl: 1)
okay, war ne doofe Frage ...
hätte ich auch gleich drauf kommen können ...
siehe Anhang (Bild) ...

stahli 30. Okt 2023 13:58

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Vielen Dank für die Infos und Hilfen!


Ich habe mir mal angehen, wie TSystemTime realisiert ist.
Nur mal eine kurze Übersicht, falls es jemanden direkt interessiert:
Delphi-Quellcode:
  PSystemTime = ^TSystemTime;
  _SYSTEMTIME = record
    wYear: Word;
    wMonth: Word;
    wDayOfWeek: Word;
    wDay: Word;
    wHour: Word;
    wMinute: Word;
    wSecond: Word;
    wMilliseconds: Word;
  end;
  {$EXTERNALSYM _SYSTEMTIME}
  TSystemTime = _SYSTEMTIME;
  SYSTEMTIME = _SYSTEMTIME;
  {$EXTERNALSYM SYSTEMTIME}
Das braucht natürlich einiges an Speicherplatz. Ich habe mich jetzt für GetTickCount entschieden, das die Systemlaufzeit als Cardinalwert zurück liefert.

Als Korrektur will ich die neue Unit nochmal hier einbinden. Vielleich hilf es ja mal jemandem.

Delphi-Quellcode:
unit myGuid;

interface

  uses

    System.Classes;

  type

    PmyGUID = ^TmyGUID;

    TmyGUID = record //: 12 Byte / 96 Bit
      C : Cardinal; //: 4 Byte / 32 Bit
      TS1: Cardinal; //: 4 Byte / 32 Bit
      TS2: Cardinal; //: 4 Byte / 32 Bit
      class function Create(const aGuid: PmyGUID): TmyGUID; overload; static;
      class function Create(const aGuid: String): TmyGUID; overload; static;
      class function Create(const aGuid: TmyGUID): TmyGUID; overload; static;
      class function CreateEmpty: TmyGUID; static;
      class function CreateNew: TmyGUID; static;
      class function StringIsValidGuid(const aGuid: String): Boolean; static;
      class operator Equal(const Left, Right: TmyGUID): Boolean;
      class operator NotEqual(const Left, Right: TmyGUID): Boolean; inline;
      function      GetHashCode: Integer;
      function      IsEmpty: Boolean;
      function      ToString: String;
      procedure     DoEmpty;
      procedure     DoNew;
      procedure     FromString(const aGuid: String);
      procedure     ReadFromStream(const aStream: TMemoryStream);
      procedure     WriteToStream(const aStream: TMemoryStream);
    end;

implementation

  uses

    System.SysUtils, System.Hash, Winapi.Windows;

  const

    MaxCardinal = 4294967295;

  var

    customTS1: Cardinal = 0;
    customTS2: Cardinal = 0;
    customC : Cardinal = 0;

  {: **************************************** TmyGUID *************************************** :}

  {: ---------------------------------------- default --------------------------------------- :}

  //: 2023-10-30
  class function TmyGUID.Create(const aGuid: String): TmyGUID;
  begin
    if (aGuid <> '') then
      begin
        Result := TmyGUID.CreateEmpty;
        Result.FromString(aGuid)
      end
    else
      begin
        Result := TmyGUID.CreateNew;
      end;
  end;

  //: 2023-10-30
  class function TmyGUID.Create(const aGuid: TmyGUID): TmyGUID;
  begin
    Result := aGuid;
  end;

  //: 2023-10-30
  class function TmyGUID.Create(const aGuid: PmyGUID): TmyGUID;
  begin
    Result := aGuid^;
  end;

  //: 2023-10-30
  class function TmyGUID.CreateEmpty: TmyGUID;
  begin
    Result.TS1 := 0;
    Result.TS2 := 0;
    Result.C  := 0;
  end;

  //: 2023-10-30
  class function TmyGUID.CreateNew: TmyGUID;
  begin
    customTS2  := GetTickCount;
    Result.TS1 := customTS1;
    Result.TS2 := customTS2;
    Result.C  := customC;
    if (customC = MaxCardinal) then
      customC := 0
    else
      Inc(customC);
  end;

  //: 2023-10-30
  class function TmyGUID.StringIsValidGuid(const aGuid: String): Boolean;
  var
    I: Integer;
    C: Char;
  begin
    //: #FFFFFFFF-FFFFFFFF-FFFFFFFF
    //: 123456789012345678901234567 - > Length = 27
    if (Length(aGuid) = 27) then
      begin
        Result := True;
        for I := 1 to Length(aGuid) do
          begin
            C := aGuid[I];
            case I of
              1:
                if C <> '#' then
                  begin
                    Result := False;
                    Break;
                  end;
              10, 19:
                if C <> '-' then
                  begin
                    Result := False;
                    Break;
                  end;
            else
              if not CharInSet(C, ['0'..'9', 'A'..'F']) then
                begin
                  Result := False;
                  Break;
                end;
            end;
          end;
      end
    else
      Result := False;
  end;

  //: 2023-10-30
  class operator TmyGUID.Equal(const Left, Right: TmyGUID): Boolean;
  begin
    Result := ((Left.TS1 = Right.TS1) and (Left.TS2 = Right.TS2) and (Left.C = Right.C));
  end;

  //: 2023-10-30
  class operator TmyGUID.NotEqual(const Left, Right: TmyGUID): Boolean;
  begin
    Result := ((Left.TS1 <> Right.TS1) or (Left.TS2 <> Right.TS2) or (Left.C <> Right.C));
  end;

  //: 2023-10-30
  function TmyGuid.GetHashCode: Integer;
  begin
    Result := 17;
    Result := Result * 397 + Integer(C);
    Result := Result * 397 + THashBobJenkins.GetHashValue(TS1, sizeOf(Cardinal), 5);
    Result := Result * 397 + THashBobJenkins.GetHashValue(TS2, sizeOf(Cardinal), 7);
  end;

  //: 2023-10-30
  function TmyGUID.IsEmpty: Boolean;
  begin
    Result := ((TS1 = 0) and (Ts2 = 0) and (C = 0));
  end;

  function TmyGUID.ToString: String;
  begin
    //: #FFFFFFFF-FFFFFFFF-FFFFFFFF
    //: 123456789012345678901234567 - > Length = 27
    Result := '#' + TS1.ToHexString + '-' + TS2.ToHexString + '-' + C.ToHexString;
  end;

  //: 2023-10-30
  procedure TmyGUID.DoEmpty;
  begin
    TS1 := 0;
    TS2 := 0;
    C  := 0;
  end;

  //: 2023-10-30
  procedure TmyGUID.DoNew;
  var
    lGuid: TmyGUID;
  begin
    lGuid := CreateNew;
    TS1   := lGuid.TS1;
    TS2   := lGuid.TS2;
    C    := lGuid.C;
  end;

  //: 2023-10-30
  procedure TmyGUID.FromString(const aGuid: String);
  begin
    //: #FFFFFFFF-FFFFFFFF-FFFFFFFF
    //: 123456789012345678901234567 - > Length = 27
    if (StringIsValidGuid(aGuid)) then
      begin
        TS1 := StrToInt('$' + Copy(aGuid, 2, 8));
        TS2 := StrToInt('$' + Copy(aGuid, 11, 8));
        C  := StrToInt('$' + Copy(aGuid, 20, 8));
      end
    else
      begin
        TS1 := 0;
        Ts2 := 0;
        C  := 0;
      end;
  end;

  //: 2023-10-30
  procedure TmyGUID.ReadFromStream(const aStream: TMemoryStream);
  begin
    aStream.ReadData(C);
    aStream.ReadData(TS1);
    aStream.ReadData(Ts2);
  end;

  //: 2023-10-30
  procedure TmyGUID.WriteToStream(const aStream: TMemoryStream);
  begin
    aStream.WriteData(C);
    aStream.WriteData(TS1);
    aStream.WriteData(Ts2);
  end;

initialization

  //: 2023-10-30
  customTS1 := GetTickCount;
  customTS2 := GetTickCount;
  customC  := 0;

end.

paule32.jk 30. Okt 2023 14:09

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Vielen Dank für Deinen Code.
Ich würde da noch eine Copyright oder PD Notiz machen ...

Nur mal so als Idee:

vielleicht könntest Du ja den Code auch dafür verwenden, wenn Du mit RPC Gedanken spielst ?
weil, für MIDL und Co. ja viele solcher GUID's verwendet werden.

vielleicht könntest Du ja noch statt einen MemoryStream, ein FileStream einbauen, damit man dann ein Template für die MIDL RPC Dingends hat.

vielleicht könntest Du dann ja auch noch TRY EXCEPT Blöcke einbauen, die dann Fehler abfangen, wenn zum Beispiel Daten geschrieben werden sollen, auf denen man dann keinen Zugriff hat ...

nur mal so gedacht...

dummzeuch 30. Okt 2023 16:08

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Zitat:

Zitat von stahli (Beitrag 1528747)
Das braucht natürlich einiges an Speicherplatz. Ich habe mich jetzt für GetTickCount entschieden, das die Systemlaufzeit als Cardinalwert zurück liefert.

Ich glaube, darüber solltest Du nochmal nachdenken, denn GetTickCount fängt beim Start des Rechners bei 0 an und hat nach ca. 21 Tagen einen Überlauf, d.h. es fängt wieder bei 0 an.

Darauf bin ich vor Jahren mal reingefallen ...

Uwe Raabe 30. Okt 2023 16:12

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Auch die Auflösung von GetTickCount ist eher überschaubar. Eventuell wäre TTimeStamp eine Alternative.

Michael II 30. Okt 2023 16:17

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Die erzeugten Werte sollten GLOBAL (GUID) möglichst kollisionsfrei sein. CreateGUID(NewGUID); guid := GUIDToString(NewGUID); schneidet wohl in den meisten Anwendungsfällen besser ab als eine "Lösung" via TDateTime oder GetTickCount. Ich nenne mal deinen Vorschlag LUID (L für lokal) und den üblichen 128 Bit Wert GUID.

TDateTime. TDateTime ist ein double. 8 Byte. Wenn du deine Funktion zwischen Jahr 1 und Jahr 9999 anbieten willst, dann speicherst du für Zeitspempel1 9999*365.25*24*60*60*1000 voneinander verschiedene Werte ab, dazu benötigst du eigentlich nur 48.5 Bits (und nicht 64). Da dein zweiter Zeitstempel z2 zeitlich nach dem ersten liegt, ist der Informationsgehalt von z2 noch tiefer. Nehmen wir mal an, z2 liege maximal 100 Jahre nach z1; dann sind das weitere 41.5 Bit Infos. Zusammen mit deinem 2 Byte Zähler, speicherst du 92 Bit Infos in deinen 144Bits, verschwendest also 52 Bits.

Eine GUID, wie du sie dir einfach via Delphi unter Windows abholen kannst nutzt global (über alle Geräte) 128 Bits.

LUID ist also 128-92=36 Bit schwächer; erzeugt 2^36 Mal weniger Werte als GUID.

Das wirkt sich natürlich sehr schlecht auf die Kollisionswahrscheinlichkeit aus.
Wie viele LUIDs kannst du ausgeben, bis die Wahrscheinlichkeit mindestens einer Kollision auf >50% steigt?
Wären deine LUIDs gleichverteilt (wäre optimal; sie sind es nicht, da du zum Beispiel im Jahr 2023 kein Zeitstempel1 2045 ausgegeben wird), dann wären es k=1/2+sqrt(1/4+2*N*ln(2))*, wobei N=2^92 die Anzahl möglicher LUIDs. Für GUIDs gilt N=2^128.

92 Bit-Werte kollidieren gemäss * bezogen auf den Fall "mind. 1 Kollision" 2^18 mal schneller als die 128 Bit GUIDs. Effektiv tun es deine LUIDs noch viel rascher, weil deine LUIDs "aufsteigend" und damit weniger "zufällig/gleichverteilt" als die GUIDs ausgegeben werden.

Rollo63 hat Infos zum Thema Kollisionen verlinkt. Es gibt dort ein Beispiel, in welchem die Ausgabe von 1 Milliarde GUIDs/sec erst nach rund 86 Jahren mit p=0.5 zu mindestens einer Kollision führt. Selbst bei optimalen 92 Bit Werten dauerte es bei gleicher Ausgabegeschwindigkeit (1 Mio 92 Bit Werte/Millisekunde(!)) nur ungefähr 3 Stunden bis es in 50% aller Fälle zu mindestens einer Kollision kommt.

Der GetTickCount Vorschlag schneidet auch nicht gut ab; da verwendest du insgesamt 4+4+4 Bytes=96 Bits.(Nebenbei: Es gibt auch GetTickCount64). GetTickCount/64 hat laut microsoft immer noch eine Auflösung von nur 10 bis 16ms (wirkt sich negativ auf die Kollisionswahrscheinlichkeit p=1-N^k/((N-k)!*N^k) aus). Bei 16ms Auflösung verlierst du zum Beispiel 2*4=8 Bits an Infos, hast also noch 88 Bytes Informationsgehalt.

Sinspin erwähnte hochauflösende Timer. Diese hätten immerhin eine bessere Auflösung als TDateTime, gettickcount, gettickcount64.

Die GUID, welche du in Delphi via CreateGUID(NewGUID); abrufen kannst sind wohl in den meisten Anwendungsfällen genügend kollisionsfrei.

Wenn du kollisionsfreie IDs benötigst, dann musst du Eigenschaften der Geräte nutzen, welche jedes Gerät eindeutig identifizieren oder aber du verwendest wie weiter oben erwähnt wurde eine zentrale Vergabestelle (da würde dann auch ein einfacher Zähler genügen).

paule32.jk 30. Okt 2023 19:45

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
ist schon interessant der Link zu Microsoft.
Allerdings weiß ich gerade nicht, wie die Testdaten zustande gekommen sind - habe das nur so flüchtig überflogen.
Aber die Tabelle mit "1 Woche Messunsicherheit von 6,08 Sekunden" ist schon nah am Limit.
Ich nehme mal an, das die modernen Computer mittels NTP Server angepasst werden, sofern Internet verfügbar ist.
Geht wohl nicht tiefer auf Comsumer PC...

skybibo 30. Okt 2023 19:57

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Zitat:

Ich glaube, darüber solltest Du nochmal nachdenken, denn GetTickCount fängt beim Start des Rechners bei 0 an und hat nach ca. 21 Tagen einen Überlauf, d.h. es fängt wieder bei 0 an.

Darauf bin ich vor Jahren mal reingefallen ...
Es sind 49 Tage. Vor ca. 20 - 25 Jahren sind viele Programme nach 49 Tage abgestürzt oder produzierten Fehler. Wobei vor 20 - 25 Jahre die Wahrscheinlichkeit, dass Windows länger als 30 Tage ohne ein Problem durchlief sehr gering.

Ich verwende daher seit Jahren GetTickCount64. Wenn dann der Zähler in ca. 585 Millionen Jahren wieder auf 0 geht interessiert mich nicht.

Sinspin 31. Okt 2023 07:35

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Zitat:

Zitat von skybibo (Beitrag 1528763)
Es sind 49 Tage. Vor ca. 20 - 25 Jahren sind viele Programme nach 49 Tage abgestürzt oder produzierten Fehler. Wobei vor 20 - 25 Jahre die Wahrscheinlichkeit, dass Windows länger als 30 Tage ohne ein Problem durchlief sehr gering.

Da gab es einige die mit Win95 Recorde aufgestellt haben. Inclusive mir.
Mein Rechner lief 24/7 unter Vollast. Erst für SETI@Home dann für Rosetta@Home. Ich brauchte im Winter jedenfalls keine Heizung.
Wenn ich mich recht erinnere wurde Windows anfangs instabil wenn man über 49 Tage kam. Das hat sich irgendwann geändert.
Nur das Problem dass die Netzwerkkarte nach einigen GB nicht mehr wollte, das blieb über ein paar Windows Versionen hinweg ein Problem. Spätestens dann war es Zeit den Rechner mal neu zu starten.

dummzeuch 31. Okt 2023 08:43

AW: TGUID - einzigartige ID auf andere Computer Systeme ?
 
Zitat:

Zitat von skybibo (Beitrag 1528763)
Zitat:

Ich glaube, darüber solltest Du nochmal nachdenken, denn GetTickCount fängt beim Start des Rechners bei 0 an und hat nach ca. 21 Tagen einen Überlauf, d.h. es fängt wieder bei 0 an.

Darauf bin ich vor Jahren mal reingefallen ...
Es sind 49 Tage. Vor ca. 20 - 25 Jahren sind viele Programme nach 49 Tage abgestürzt oder produzierten Fehler. Wobei vor 20 - 25 Jahre die Wahrscheinlichkeit, dass Windows länger als 30 Tage ohne ein Problem durchlief sehr gering.

Ich verwende daher seit Jahren GetTickCount64. Wenn dann der Zähler in ca. 585 Millionen Jahren wieder auf 0 geht interessiert mich nicht.

Wie einen die Erinnerung doch täuschen kann. Ich hatte kurz überlegt, es nachzurechnen, war aber dann zu faul. Zu meiner Entlastung: Es ist so ca. 25 Jahre her, dass ich mich mit dem Problem auseinandersetzen musste. Eines der Programme, die bei diesem Überlauf abstürzten, war meines (allerdings wurde das nur intern verwendet). Damals ging es um Windows NT4 und das lief über Monate stabil (Win95/98/ME brauchte ich zum Glück nie benutzen). GetTickCount64 gab es damals noch nicht, soweit ich mich errinnere. Ich meine, ich hätte damals dann "einfach" den Überlauf im Code berücksichtigt.

/AlterMannGebrabbelEnde


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:12 Uhr.
Seite 1 von 2  1 2      

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