c / c ++ - sicherste Möglichkeit, time_t über Socket zu senden

8

Ich habe eine C ++ - Server / Client-Umgebung eingerichtet und versuche, einen time_t-Wert vom Server an den Client zu senden (eine nützliche Sache auf jedem Server). Aber ich bekomme Kopfschmerzen: time_t scheint unter keinen Größenangaben zu stehen. Ich frage mich, was ist die sicherste (portabler) Art und Weise zu senden time_t über das Netzwerk.

Dies ist ein kleines Beispiel:

%Vor%

Ich habe zwei Probleme:

  • time_t ist nicht size-fixed
  • time_t kann ein typedef eines vorzeichenbehafteten oder vorzeichenlosen ganzzahligen Datentyps
  • sein

Wie kann ich diese zwei Probleme behandeln, damit ich sie sicher zwischen (fast) jeder Architektur senden kann?

Vielen Dank im Voraus.

EDIT: Nachdem ich die gleichen drei Antworten gesehen habe, finde ich es besser, hier zu antworten. Es tut mir leid, dass ich das vorher nicht geklärt habe. Ich bevorzuge es in 'reinen' Bytes zu senden, obwohl das Senden als String kein Problem ist. Soweit ich weiß, muss ich (wieder) die Signedness und die Größe des Datentyps time_t im Host-System berücksichtigen, oder? (Danke und Entschuldigung)

    
shura-astrozero 19.12.2012, 16:54
quelle

4 Antworten

13

Erstens, ich denke, Sie müssen entscheiden, ob Sie sich mit dem Problem befassen wollen, dass der C-Standard die Bedeutung von time_t zu vage lässt (es ist nicht unbedingt in Sekunden dargestellt und hat auch keine aussagekräftigen numerischen Eigenschaften wie Bestellung / Vergleich). Dies widerspricht dem Verhalten von jeder vorhandenen und historischen Implementierung, wobei time_t in Sekunden angegeben ist. Sowohl C als auch POSIX erlauben auch, dass time_t ein Fließkommatyp ist; Soweit ich weiß, machen das keine Implementierungen aus, und auf POSIX wäre das ziemlich schädlich, da der Wert von time_t eine Ganzzahl sein muss, wie sie in struct timespec verwendet wird .

Wenn Sie sich entscheiden, dass Sie zufrieden sind, wenn time_t immer eine ganzzahlige Anzahl von Sekunden seit der Epoche ist, dh die Werte für den Austausch zwischen Systemen bedeutsam sind, dann müssen Sie sie nur formatieren . Am sichersten wäre es, einen Integer-Typ zu erzeugen, der groß genug ist, um einen sinnvollen Wert zu speichern, und der auf allen Systemen die gleiche Größe hat: das wäre int64_t . Verwenden Sie dann die normalen Mittel, die Sie zum Serialisieren von int64_t auf eine Art verwenden, die gegen Endian-Unterschiede immun ist.

Wenn Sie andererseits "absolut" portabel sein möchten, sollten Sie Ihren eigenen time_t -Wert für "die Epoche" (entweder den Standard oder Ihre eigene Epoche) berechnen und dann difftime verwenden konvertiert in ein Double, das "Sekunden seit der Epoche" darstellt, und formatiere double mit snprintf(buf, sizeof buf, "%.0f", diff) . Beachten Sie, dass die Berechnung eines time_t -Werts für die Epoche in Portable C ziemlich schwierig ist, da die meisten Standardfunktionen in lokaler Zeit arbeiten, während Sie universelle Zeit benötigen. Es gibt Tricks, die Sie mit den Funktionen gmtime , mktime und localtime ausführen können, um es herauszufinden, aber es ist nicht trivial ...

    
R.. 19.12.2012 17:00
quelle
3

Sie können es in Textform mit einer festen Anzahl von Ziffern senden. Dann müssen Sie sich nicht um Zeichen, Größeninkompatibilitäten oder sogar die Byte-Reihenfolge kümmern.

    
Some programmer dude 19.12.2012 16:58
quelle
3

Sie könnten eine Textdarstellung senden, die von strftime in Kombination mit gmtime erstellt wurde. Die Darstellung wäre etwas größer als eine Binärdarstellung, aber nicht groß. Z. B. erzeugt die Formatzeichenkette "%Y%j%H%M%S" eine 13-Byte-Darstellung eines Zeitpunkts (ausschließlich eines NUL-Zeichens).

BEARBEITEN : Vergessen Sie meinen vorherigen Hinweis, ctime zu verwenden; das verwendet localtime und würde daher nur funktionieren, wenn sich Client und Server in derselben Zeitzone befinden. Und anscheinend ist asctime unsicher, also benutze strftime .

    
Fred Foo 19.12.2012 16:57
quelle
0

Ich habe gerade ein ähnliches Problem, und ich denke, es wäre nett, einige Anweisungen zu haben, wie man das durchmacht. Beachten Sie, dass diese Lösung hier POSIX.1-2001 kompatibel sein sollte (auf Ubuntu 14.04, man tzset und man localtime gibt solche Informationen, und ich habe wirklich keine anderen Quellen verwendet).

Verwenden Sie localtime , um die aus Ihrem Aufruf erhaltenen Daten in time in ein struct tm zu konvertieren (siehe time.h ):

%Vor%

Beachten Sie, dass localtime die Variable deklariert als (siehe auch time.h )

%Vor%

Da alle Typen jetzt bekannt sind, können Sie Ihr eigenes Konvertierungstool schreiben, um dieses Datennetzwerk portabel zu machen. Dinge zu beachten:

  • (vorzugsweise in Ihrer Software init), müssen Sie bestimmen, wie viele Bytes Ihre int und long haben (verwenden Sie sizeof , natürlich)
  • Basierend auf diesen Informationen könnten Sie eine Host-zu-Netzwerk-Konvertierung für jedes Ganzzahl-Feld von struct tm durchführen (verwenden Sie htonl oder htons - für 64-Bit-Typen müssen Sie Ihre eigenen schreiben) und senden Sie diese Information an den Client (wie Sie wollen).
    Wenn Sie einen Zeitzonenunterschied haben, müssen Sie auch Zeitzoneninformationen konvertieren / senden, dh die Daten, die in der Variable timezone (siehe oben).
  • Der Kunde muss dann

    1. Konvertieren Sie die empfangenen Daten in die Client-Byte-Reihenfolge
    2. Schreiben Sie es in ein struct tm (wenn Zeitzonen beteiligt sind, schreiben Sie die empfangenen Zeitzonendaten in ein long )
    3. Wenn Zeitzonen involviert sind , schreibe die empfangenen Zeitzonendaten in ein long und berechne die Zeitzonendifferenz (berechne die Differenz des empfangenen timezone -Datums und was du bekommst, indem du tzset lokal aufrufst ...), passen Sie dann die in Schritt 2 erstellte Variable struct tm an.
    4. Nachdem Sie struct tm an die lokale Zeitzone des Kunden angepasst haben, verwenden Sie mktime , um Daten in ein time_t zurück zu konvertieren.
    5. Konto für den Zeitzonenunterschied, falls vorhanden.
polynomial_donut 13.03.2018 21:00
quelle

Tags und Links