Autor |
Beitrag |
Burgpflanze
      
Beiträge: 67
Windows2000 Prof. SP4
Delphi7 Enterprise
|
Verfasst: 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
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
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: 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
|
Verfasst: 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 |
 Wo?
|
|
matze
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: 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
|
Verfasst: 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
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: 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
|
Verfasst: 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
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: 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
|
Verfasst: Mi 08.01.03 21:20
nonVCL = Handarbeit.
VCL = Klickibunti.

|
|
matze
      
Beiträge: 4613
Erhaltene Danke: 24
XP home, prof
Delphi 2009 Prof,
|
Verfasst: 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
|
Verfasst: Mi 08.01.03 21:38
Wenn es sich meldet und die entsprechenden Links postet, dann kann man ihm auch weiterhelfen.
|
|
Burgpflanze 
      
Beiträge: 67
Windows2000 Prof. SP4
Delphi7 Enterprise
|
Verfasst: Do 09.01.03 15:19
Hab Lösung gefunden
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
|
Verfasst: Do 09.01.03 17:23
Puh:
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:
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.
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 
      
Beiträge: 67
Windows2000 Prof. SP4
Delphi7 Enterprise
|
Verfasst: 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
Das Ergebnis ist auch nicht dasselbe.
Aber so geht es auch:
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
|
Verfasst: 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 ... 
|
|
Burgpflanze 
      
Beiträge: 67
Windows2000 Prof. SP4
Delphi7 Enterprise
|
Verfasst: 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:
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:
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
Bis demnächst,
Burgpflanze
|
|
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: 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
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 
      
Beiträge: 67
Windows2000 Prof. SP4
Delphi7 Enterprise
|
Verfasst: 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
|
Verfasst: 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:
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:
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:
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:
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
Quelltext
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
|
Verfasst: Sa 11.01.03 16:25
Ja, lad das bitte mal hoch, das will ich mir mal ansehen.
|
|
|