Autor Beitrag
Burgpflanze
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 67

Windows2000 Prof. SP4
Delphi7 Enterprise
BeitragVerfasst: Mi 08.01.03 12:27 
Wenn ich zu einem Time-Server auf Port 37 connecte, bekomme ich als Antwort einen 4 Byte langen Wert, den ich mittels
ausblenden Quelltext
1:
error := recv(sock_handle, ut, 4, 0);					

in eine Variable (ut) vom Typ Cardinal einlese.

Mein Problem ist nun, wie ich diesen Wert in die Systemzeit (_SYSTEMTIME) umrechnen muss, damit ich meine PC-Uhr mit der Internet-Zeit synchronisieren kann, und das ohne VCL, womit also auch die IdTime-Komponente ausscheidet.

Wer weiß, wie es gemacht wird? Mir helfen leider nicht die vielen Code-Beispiele in C, die ich im Internet gefunden habe :?

Vielen Dank schon mal.


Gruss, Burgpflanze
matze
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: Mi 08.01.03 18:26 
du kannst die indy komoos doch auch hernehmen, wenn du nonvcl codest !!! lies dir ambesten mal die tuts auf www.luckie-online.de durch. da wird beschrieben, wie man kompos auch bei nonvcl hernimmt

_________________
In the beginning was the word.
And the word was content-type: text/plain.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 08.01.03 18:43 
matze hat folgendes geschrieben:
du kannst die indy komoos doch auch hernehmen, wenn du nonvcl codest !!! lies dir ambesten mal die tuts auf www.luckie-online.de durch. da wird beschrieben, wie man kompos auch bei nonvcl hernimmt

:shock: Wo?
matze
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: Mi 08.01.03 18:55 
war das nicht bei dir ???? mist

_________________
In the beginning was the word.
And the word was content-type: text/plain.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 08.01.03 18:58 
Nicht das ich wüßte.

Aber probier mal etwas mit TSYSTEMTIME und TFILETIME rum. Das BVuch, wo ich es drin stehen habe, hab eich leider zu Hause und jetzt nicht hier griff bereit.

Und poste mal die Links zu den C-Beispielen, dan kann man sich das mal ankucken.
matze
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: Mi 08.01.03 19:12 
aber mann kann doch auch VCL kompos beim nonvcl coden hernehmen oder ??

_________________
In the beginning was the word.
And the word was content-type: text/plain.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 08.01.03 19:21 
Wie? Was für ein Objekt willst du als Parent oder Owner angeben? Du hast ja gerade kein Objekt TForm. Das ist ja gerade der Gag. das einzigste, was gehen würde, du schreibst die Kompo zu einer Unit um. Ist aber viel Arbeit und eventuell nicht immer zu realisieren.
matze
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: Mi 08.01.03 21:17 
dann ist das ja nicht wirklich komfortabel !!!

_________________
In the beginning was the word.
And the word was content-type: text/plain.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 08.01.03 21:20 
nonVCL = Handarbeit.
VCL = Klickibunti.

:mrgreen:
matze
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 4613
Erhaltene Danke: 24

XP home, prof
Delphi 2009 Prof,
BeitragVerfasst: Mi 08.01.03 21:24 
also luckie: damit wir hier nicht das topic vollabern und das eigendliche thema verfehlen: www.auq.de/viewtopic.php?p=28522#28522

_________________
In the beginning was the word.
And the word was content-type: text/plain.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 08.01.03 21:38 
Wenn es sich meldet und die entsprechenden Links postet, dann kann man ihm auch weiterhelfen.
Burgpflanze Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 67

Windows2000 Prof. SP4
Delphi7 Enterprise
BeitragVerfasst: Do 09.01.03 15:19 
Hab Lösung gefunden 8)

ausblenden volle Höhe Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
// Nur WinNT 3.5 und höher, Win2000 und WinXP, 
// da nur diese Versionen intern mit GMT-Zeit arbeiten,
// ansonsten muss die Zeitzone berücksichtig werden
function SetTimeFromInternet(buf: array of Char): Integer;
var
  umt: Int64;
  ft: _FILETIME;
  st: _SYSTEMTIME;
  li: ULARGE_INTEGER;
begin
  Result := 0;

  umt := Ord(buf[0]) * 256 * 256 * 256 + Ord(buf[1]) * 256 * 256 +
      Ord(buf[2]) * 256 + Ord(buf[3]);

  st.wYear := 1900;
  st.wMonth := 1;
  st.wDayOfWeek := 0;
  st.wDay := 1;
  st.wHour := 0;
  st.wMinute := 0;
  st.wSecond := 0;
  st.wMilliseconds := 0;

  if not SystemTimeToFileTime(st, ft) then
  begin
    Result := GetLastError;
    Exit;
  end;

  li.QuadPart := umt * 10000000;
  li.QuadPart := li.QuadPart + ULARGE_INTEGER(ft).QuadPart;

  if not FileTimeToSystemTime(_FILETIME(li), st) then
  begin
    Result := GetLastError;
    Exit;
  end;

  if not SetSystemTime(st) then Result := GetLastError;
end;


Aber trotzdem danke!

Gruss, Burgpflanze
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 09.01.03 17:23 
Puh:
ausblenden Quelltext
1:
2:
umt := Ord(buf[0]) * 256 * 256 * 256 + Ord(buf[1]) * 256 * 256 +
  Ord(buf[2]) * 256 + Ord(buf[3]);

:?

Wäre es nicht a) besser, die vier Bytes gleich als solche zu übergeben, und b) sinnvolle Funktionen des Systems zu nutzen? bspw:
ausblenden Quelltext
1:
umt := MAKELONG(MAKEWORD(buf[3],buf[2]),MAKEWORD(buf[1],buf[0]));					

Das Ergebnis wäre das gleiche. Die Sache sieht allerdings gefälliger aus, und da die Funktionen Teil der Windows-Unit sind, spricht doch auch nichts gegen ihre Verwendung. :wink:

Warum ist diese "Umwandlung" eigentlich erforderlich? Hm, vielleicht sollte ich mir das Protokoll und ein paar Beispiele mal ansehen, damit ich das nachvollziehen kann ...
Burgpflanze Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 67

Windows2000 Prof. SP4
Delphi7 Enterprise
BeitragVerfasst: Fr 10.01.03 16:47 
Hallo Matthias,

so wie du es machen würdest, geht es aber nicht,
zumal du ein Char nicht als Byte übergeben kannst :wink:

Das Ergebnis ist auch nicht dasselbe.

Aber so geht es auch:
ausblenden Quelltext
1:
umt := Ord(buf[0]) shl 24 + Ord(buf[1]) shl 16 + Ord(buf[2]) shl 8 + Ord(buf[0]);					


Gruss, Burgpflanze
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 10.01.03 19:30 
*hi hi* Du hast Punkt A vergessen:
MathiasSimmack hat folgendes geschrieben:
Wäre es nicht a) besser, die vier Bytes gleich als solche zu übergeben, ...

Unter der Maßgabe, der Puffer wäre also kein "array of char" sondern ein "array of byte", habe ich die Funktionen MAKELONG/MAKEWORD benutzt. Und bei allen Versuchen waren die Ergebnisse mit deiner Methode und mit meinem Weg irgendwie immer identisch.

Wann unterscheiden sich die Ergebnisse?
Und noch mal: warum diese Trennung in 4 einzelne Bytes (ausgehend von der Vermutung, dass es sich dabei um den 4-Byte-Wert des Time-Servers handelt) und "Drehung"?

Ja ja, ich bin neugierig ... :wink:
Burgpflanze Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 67

Windows2000 Prof. SP4
Delphi7 Enterprise
BeitragVerfasst: Fr 10.01.03 20:34 
Ich muss dir leider widersprechen - die Ergebnisse sind nicht gleich - warum auch immer :(

Und nun zu meiner Vorgehensweise:

- Connect zu einem Zeitserver (ich nehme ntpserv.fh-magdeburg.de, weil
dieser nur 30 km von mir entfernt ist, es geht aber auch jeder andere,
wenn er über Port 37 zu erreichen ist)

- Dann lese ich die Antwort auf den Connect aus:
ausblenden Quelltext
1:
2:
3:
var buf: array[0..3] of Byte; // Nicht lachen jetzt

error := recv(socket_handle, buf, 4, 0);


Theoretisch kann man auch eine Integer-Variable als Buffer verwenden,
jedoch stimmt dann das Ergebnis überhaupt nicht mehr, auch wenn man,
wie in den von mir gefundenen C-Beispielen gemacht, folgendes macht:
ausblenden Quelltext
1:
2:
3:
4:
var buf: Integer;

error := recv(socket_handle, buf, 4, 0);
buf := htonl(buf);


Das von mir zur Zeit eingesetzte Verfahren ist eine Kombination aus
einem VB-Beispiel und einem C-Beispiel und funktioniert.

Warum nun aber dieser Byte-Dreher gemacht werden muss?

Die Antwort des Servers kommt in "host byte order" und muss in "TCP/IP network byte order" umgerechnet werden.

Leider kann ich dir nicht mehr dazu sagen, da ich ganz sicher kein
Spezialist des NTP-Protokolls bin :D


Bis demnächst,
Burgpflanze
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 10.01.03 22:13 
Ich habe mir gerade mal fix ein Mini-Tool geschrieben, das sich zweimal mit dem Server verbindet und die Zeit holt. Einmal als Integer und einmal als Byte-Array. "Drehe" ich die Integer-Variable mit htonl und lasse mir beides (hexadezimal) in zwei Edits anzeigen, ist´s der selbe Wert wie das Byte-Array.

Übergebe ich die Integer-Variable aber an deine Funktion, "SetTimeFromInternet" (die mir aber nicht die Zeit verstellt, sondern die ermittelte Zeit in einem dritten Edit darstellt), kommt irgendwas als Ergebnis; nicht jedoch die tatsächliche Uhrzeit. Ich habe natürlich diese Zeile
ausblenden Quelltext
1:
li.QuadPart := umt * 10000000;					

geändert, da die Int64-Variable mit dem eigentlich korrekten Wert bereits im Funktionskopf angegeben wird.

Hm ... :?
Ich denke, ich habe bloß was übersehen; denn logisch betrachtet sollte es gehen. Der Wert ist ja der selbe ...
Burgpflanze Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 67

Windows2000 Prof. SP4
Delphi7 Enterprise
BeitragVerfasst: Fr 10.01.03 22:27 
Du kannst mir deinen Code ja mal schicken, entweder hier als Posting oder per e-Mail.

Dieser Multiplikator (10000000) scheint aber notwendig zu sein, zumindest
war er in allen C-Beispielen vorhanden.

Gruss, Burgpflanze
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 11.01.03 13:42 
Jetzt geht´s auch mit Cardinal. Merkwürdig ... Also, gut. Kurz zum Programm: es ist ein NonVCL-Dialog mit vier Edits:
ausblenden Quelltext
1:
2:
3:
4:
5:
const
  IDC_BYTEARRAY  = 110;
  IDC_CARDINAL   = 111;
  IDC_BYTEMEANS  = 112;
  IDC_CARDMEANS  = 113;

Ein Timer wird jede Sekunde aktiv:
ausblenden volle Höhe Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
    WM_TIMER:
      if(wp = IDC_TIMER) then begin
        hostent := gethostbyname('ntpserv.fh-magdeburg.de');

        // als Byte-Array lesen
        s       := socket(PF_INET,SOCK_STREAM,0);
        if(s <> INVALID_SOCKET) and (hostent <> nil) then begin
          SetLength(b,4);

          ZeroMemory(@saddr,sizeof(TSockAddr));
          saddr.sin_addr.S_addr := integer(pointer(hostent^.h_addr_list^)^);
          saddr.sin_family      := PF_INET;
          saddr.sin_port        := htons(37);

          res                   := connect(s,saddr,sizeof(TSockAddr));
          if(res <> SOCKET_ERROR) then
            res                 := recv(s,b[0],length(b),0);

          // Byte-Array anzeigen, ...
          if(res <> SOCKET_ERROR) then
            SetWindowText(GetDlgItem(hwndDlg,IDC_BYTEARRAY),
            pchar(Format('%.2x %.2x %.2x %.2x',[b[0],b[1],b[2],b[3]])));

          // ... & Zeit berechnen
          SetTimeFromInternet(@b,nil,GetDlgItem(hwndDlg,IDC_BYTEMEANS));
          SetLength(b,0);

          CloseSocket(s);
        end;

        // als Cardinal lesen
        s       := socket(PF_INET,SOCK_STREAM,0);
        if(s <> INVALID_SOCKET) and (hostent <> nil) then begin
          ZeroMemory(@saddr,sizeof(TSockAddr));
          saddr.sin_addr.S_addr := integer(pointer(hostent^.h_addr_list^)^);
          saddr.sin_family      := PF_INET;
          saddr.sin_port        := htons(37);

          res                   := connect(s,saddr,sizeof(TSockAddr));
          if(res <> SOCKET_ERROR) then
            res                 := recv(s,i,sizeof(i),0);

          if(res <> SOCKET_ERROR) then
            // Cardinal-Wert "drehen" (host byte order -> TCP/IP network byte order)
            i                   := htonl(i)
          else
            i                   := 0;

          // Cardinal als 8-stelligen Hex-Wert anzeigen, ...
          if(res <> SOCKET_ERROR) then
            SetWindowText(GetDlgItem(hwndDlg,IDC_CARDINAL),
            pchar(Format('0x%.8x',[i])));

          // ... & Zeit berechnen
          SetTimeFromInternet(nil,@i,GetDlgItem(hwndDlg,IDC_CARDMEANS));

          CloseSocket(s);
        end;

Die Variablen fix:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
type
  TBArray = array of byte;
  PBArray = ^TBArray;
var
  hostent   : PHostEnt;
  s         : TSocket;
  saddr     : TSockAddr;
  res       : integer;
  b         : TBArray;
  i         : cardinal;

Und deine umgeschriebene Funktion, die mir nur die Zeit anzeigt aber nicht verstellt:
ausblenden volle Höhe Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
procedure SetTimeFromInternet(b: PBArray; i: PDWORD; wnd: HWND);
var
  umt : int64;
  st  : TSystemTime;
  ft  : TFileTime;
  li  : ULARGE_INTEGER;
  buf : array[0..MAX_PATH]of char;
begin
  if(b = nil) and (i = nil) then exit;

  if(i = nil) then umt := b^[0] shl 24 +
                          b^[1] shl 16 +
                          b^[2] shl 8  +
                          b^[3]
  else umt := i^;

  st.wYear         := 1970;
  st.wMonth        := 1;
  st.wDayOfWeek    := 0;
  st.wDay          := 1;
  st.wHour         := 0;
  st.wMinute       := 0;
  st.wSecond       := 0;
  st.wMilliseconds := 0;
  if(not SystemTimeToFileTime(st,ft)) then exit;

  li.QuadPart      := (umt * 10000000) + ULARGE_INTEGER(ft).QuadPart;
  if(not FileTimeToSystemTime(TFileTime(li),st)) then exit;

  ZeroMemory(@buf,sizeof(buf));
  if(GetTimeFormat(LOCALE_USER_DEFAULT,
    TIME_FORCE24HOURFORMAT,
    @st,
    nil,
    buf,
    sizeof(buf)) > 0) then SetWindowText(wnd,buf);
end;

Ich habe mich für Zeiger entschieden, weil die Prüfung so einfacher ist. Da "b" ja ein Array ist, kann man (IMHO?) nicht einfach
ausblenden Quelltext
1:
if b = 0					

prüfen.


So, nun frag mich aber bitte nicht, was ich gestern falsch gemacht habe ... Ich weiß es nicht ... :?

Ach ja: Wer´s probieren will - "WsaStartup" und "WsaCleanup" nicht vergessen. Auf Wunsch kann ich aber auch gern das Ding hochladen; daran soll´s nicht scheitern.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 11.01.03 16:25 
Ja, lad das bitte mal hoch, das will ich mir mal ansehen.