[DELPHI] Record über Netzwerk senden

thilo85

Newbie
Registriert
Mai 2004
Beiträge
1
Hallo Leute,

Also, habe folgendes Problem:

Hab nen Record hier, sagen wir mit folgenden Daten:
Code:
MyRecord = record
  name1, name2 : string[30];
  alter1, alter2 : byte;
end;

Dieses Record möchte ich nun über ein Netzwerk senden. Habe einen Server, der alle Daten aufnimmt & verwaltet. Dieser soll das Record empfangen und dann weiterverarbeiten (Legt den Datensatz in ne doppelt verkettete Liste).
Jedoch kann ein Client auch sagen: "Gib mir mal bitte Datensatz 12". Dann soll der Server Ihm den 12. Datensatz schicken, auch als oben definiertes Record.

So, meine Fragen:
1. Wie kann ich von dem Client ein Record an den Server schicken?
2. Kann der Server ein Record an den Client schicken? Wenn ja, wie?


Regards,
thilo

[Edit]Achja, läuft alles über TServerSocket & TClientSocket
 
Datenserialisierung, clientseitiger Teil und Request-Protokoll

Also. Mit den Delphi-Sockets kenne ich mich nicht aus, da Delphi nie bei mir lief :D

Im Prinzip musst du erstmal zwei Funktionen machen um einen Record in einen String umzuwandeln und umgekehrt.
Dazu speicherst du in einem Byte binär die Länge des ersten Strings (Chr(Len(stringvariable)) oder sowas, dann den String selbst. Das gleiche machst du mit dem zweiten String. Danach noch je ein Byte binär anhängen für die Altersangaben.
Umgekehrt liest du aus dem übergebenen String das erste Zeichen aus, wandelst es in ein Byte um. Dadurch weisst du, wie viele der folgenden Bytes den String enthalten. Diese liest du aus und speicherst sie als name1. Das gleiche wiederholst du für name2 und dann die letzten beiden Bytes wieder fürs Alter.

Jetzt kannst du aus deinem komplexen Typ MyRecord den einfachen und problemlos übertragbaren Typ string machen, diesen übertragen und dann wieder umwandeln in einen Record. So viel dazu.

Dann benötigst du irgendein Protokoll. Am einfachsten wäre es vielleicht, sich dafür an HTTP zu orientieren: Die erste Zeile gibt an, was gemacht werden soll und der Rest gilt als RAW-Data (d.h. alle weiteren Zeilenumbrüche etc. werden als Daten gewertet und nicht als Formatierung).


Die erste Zeile könnte dann wie folgt aussehen:
METHOD RESSOURCE BODYLENGTH CrLf

CrLf ist einfach ein Zeilenumbruch, der aus den Zeichen ASCII-10 ASCII-13 besteht (Chr(10)+Chr(13) oder sowas... kA, ich bin PHPler und C++ler). Er ist nötig, damit du weisst, wann die erste Zeile zu Ende ist.

BODYLENGTH gibt an, wie viele Zeichen nach dem CrLf noch folgen. Es ist eine nichtnegative ganze Zahl, die ausgeschrieben gespeichert wird, nicht binär (da sie binär die Zeichenfolge CrLf enthalten könnte).

METHOD und RESSOURCE musst du dir selber ein Format ausdenken, dass deinen Anforderungen entspricht. Möglich wäre z.B.

METHOD: GET um Datensätze abzufragen und PUT um welche zu schreiben. Dabei gibst du den gewünschten Datensatz an mit:

RESSOURCE: /records/recordid, also z.B. für den Record mit dem Index 5: /records/5
Dazu dann zum Records vorne und hinten Einfügen vielleicht noch /records/begin und /records/end. Falls diese mit GET abgerufen werden geben sie einfach den ersten oder den letzten Datensatz zurück.
 
Zuletzt bearbeitet: (Vernünftiger Titel.)
Beispiele: Client -> Server

Um das mal als Beispiel durchzuführen:
Wir wollen den Record mit dem Index 4 überschreiben mit den folgenden Daten:
name1="Tom"
name2="Methusalem"
alter1=65
alter2=109
Dazu wandeln wir den Record in einen String um (die kursiven Zahlen sind EIN EINZIGES Zeichen mit dem Wert der Zahl):
3Tom10MethusalemAm
Das sind 1 + 3 + 1 + 10 + 1 + 1 = 17 Zeichen

PUT /records/4 17 CrLf
3Tom10MethusalemAm

_____


Oder wir wollen den letzten Record abfragen... d.h. wir übermitteln keine Daten sondern erwarten welche:
GET /records/end 0 CrLf
 
Zuletzt bearbeitet: (Vernünftiger Titel.)
Serverseitiger Teil und Antwortprotokoll

Das war der Teil Client -> Server.
Jetzt kommt der Teil Server -> Client:

Der Server prüft immer wenn er Daten empfangen hat, ob ein CrLf in diesen Daten vorkommt. Sobald dies das erste Mal der Fall ist wertet er die erste Zeile aus und wartet darauf, dass die angegebene Anzahl an Datenbytes übermittelt wurde.
Sobald dies geschehen ist fängt er an:
1.: Ist METHOD eine bekannte Methode?
2.: Ist RESSOURCE eine gültige Ressource?
3.: Darf man überhaupt mit METHOD auf RESSOURCE zugreifen?
4.: eventuelle weitere Prüfungen.

Auf die eine oder andere Art wird der Server zu einem Ergebnis kommen. Dieses sollte dem Client IMMER berichtet werden, deswegen braucht man auch für die Antwort erst einmal einen Statusheader, der ähnlich aufgebaut ist wie die erste Zeile der Anfrage:
STATUSCODE BODYLENGTH CrLf

BODYLENGTH und CrLf sind schon bekannt.

STATUSCODE ist einfach ein festgelegter Code, der Angibt, was genau passiert ist. Das könnte z.B. sein:
OK - Die Anfrage wurde ausgeführt, es werden aber keine vom Programm zu verarbeitenden Daten zurückgegeben. (Eventuell mitgelieferte Daten könnten dann z.B. ein Hinweistext sein wie "Anfrage erfolgreich" oder so, der aber maximal für den Nutzer interessant ist und nicht für den Client)
DATA - Das Programm hat Daten angefordert und bekommt diese jetzt zurückgeliefert.
UNKNOWN_METHOD - Die Methode ist nicht bekannt. Z.B. wurde statt GET oder PUT z.B. HEAD (eine oft benutzte Methode in HTTP) benutzt.
NOT_FOUND - Die Ressource existiert nicht. Z.B. gibt es nur 19 Datensätze und das Programm versucht, den Datensatz mit dem Index 100 abzurufen.
NO_DATA - Es wurde versucht, einen Datensatz zu (über)schreiben, aber keine Daten mitgeliefert.
WRONG_DATA - Es wurden zwar Daten mitgeliefert, aber im falschen Format.
und und und... die Liste der möglichen Status-Codes kann beliebig erweitert werden.
 
Zuletzt bearbeitet: (Vernünftiger Titel.)
Beispiele: Server -> Client

Wir verwenden wieder die Beispiele von oben:

1. Beispiel:
Anfrage:
PUT /records/4 17 CrLf
3Tom10MethusalemAm

Angenommen, es gibt Record 4 schon und alles klappt (genügend Festplattenspeicher auf dem Server, etc etc...), dann lautet die Antwort vom Server:
OK 0 CrLf
kein Datenteil

Sollten hingegen erst die Records 1 und 2 bestehen und 4 deswegen noch nicht schreibbar sein (da zunächst noch 3 eingetragen werden muss), so wird ein Fehler gemeldet:
NOT_FOUND 0 CrLf
kein Datenteil

Eventuell sogar mit einer Nachricht, die dem Benutzer den genauen Fehlergrund erklärt:
NOT_FOUND 87 CrLf
Der angegebene Datensatz existiert noch nicht und kann daher nicht aktualisiert werden.

_____


2. Beispiel:
Wir nehmen an, dass es insgesamt vier Datensätze (1 - 4) gibt, von denen ja der letzte abgerufen werden soll.
Der Datensatz wird ausgelesen und (siehe 1. Post: Serialisierung, clientseitiger Teil und Request-Protokoll) in einen String umgewandelt.
Die Länge des Strings ist dann 17, wie im clientseitigen Teil dieses Beispiels ermittelt wurde. Die Antwort wäre dann:
OK 17 CrLf
3Tom10MethusalemAm
 
Zuletzt bearbeitet:
Zurück auf dem Client und Erweiterungsvorschläge

Nachdem der Client die Antwort vom Server ausgewertet hat handelt er entsprechend dem Status-Code. Sollten Daten zurückgeliefert worden sein dann decodiert er sie zu einem Record, der dann weitererwendet werden kann.

Erweitern könnte man dieses System jetzt zum Beispiel noch um die Ressource /records/count, die dann die Zahl der gespeicherten Records zurückliefert.
Dabei ist zu beachten, dass man diese Zahl ja nicht schreiben kann, PUT /records/count müsste zum Beispiel einen Fehler zurückgeben (da bisher nichts geeignetes definiert ist müsste dann ein neuer Code wir z.B. METHOD_NOT_ALLOWED zurückgegeben werden, wenn so etwas versucht wird.)

Es könnten auch neue Methoden eingeführt werden. Sinnvoll wäre zum Beispiel DELETE... etc.

Viel Spass dabei. :)

___


Achso... falls du dich genauer über das HTTP-Protokoll informieren möchtest: http://www.google.de/search?q=rfc2616 davon einfach eine Version (für den Fall, dass wider Erwarten ein RFC-Mirror dichtmacht gibts dort immernoch die anderen). Die sind zwar alle Englisch, dafür aber die exakteste Dokumentation für ein bestimmtes Protokoll.
(btw... ich hab da echt 50min dran gesessen, das zu schreiben?! O_o)
 
Zuletzt bearbeitet:
Zurück
Oben