Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Client/Serververbindung arbeitet kurz und friert dann ein. (https://www.delphipraxis.net/73467-client-serververbindung-arbeitet-kurz-und-friert-dann-ein.html)

BlackJack 18. Jul 2006 16:55


Client/Serververbindung arbeitet kurz und friert dann ein.
 
Liste der Anhänge anzeigen (Anzahl: 1)
Moin,
ich habe ein paar Probleme mit einer Client-Server-Verbindung (mit TServerSocket & TClientSocket). Und zwar möchte ich mir einen Netzwerkrenderer für meinen Raytracer programmieren (spielt aber erstmal keine Rolle). Das ganze soll so ablaufen:
  • Der Client schickt ne Nachricht zum Server, das er gerne ne Aufgabe hätte ("givejob")
  • Der Server schickt einen Auftrag zum Client, was dieser tun soll ("dojob"),
  • Der Client macht, was er tun soll, d.h. er rechnet ein bisschen rum
  • Wenn er damit fertig ist, schickt der dem Server die Ergebnisse zurück ("donejob")
  • Der Server bestätig dem Client, dass die Ergebnisse angekommen sind ("datareceived")
  • Danach kann sich der Client n neuen Auftrag holen; wenn es nichts mehr zu tun gibt, anwortet der Server mit "nomorejobs"
Für das Übermittel der Nachrichten hab ich mir auch schön ein Protokoll ausgedacht: zuerst wird eine Signatur übermittelt ("lrt"), dann ein byte, das die Länge der nachfolgenden Zeichenkette angibt, und in der Zeichenkette stehen dann halt die "Auftragsstrings" drin (givejob, dojob etc.).

Im Prinzip funktioniert das ganze auch ansatzweise, allerdings kommt beim Server nach ein paar Aufträgen nichts mehr an. Und mit zwei Clients gleichzeitig kann der Server auch nicht arbeiten, dann friert er einfach so lange ein, bis einer der Clients wieder disconnected.

Meine Frage ist jetzt erstmal (da ich mich gerade erst in das Thema TCP/IP), ob ich überhaupt die Nachrichten und Daten zwischen Server richtig austausche; die entsprechenden Routinen stehen in der Unit TCPUtils.pas, aber ich poste sie trotzdem nochmal hier.

Desweiteren wolle ich mal fragen, wie man das am Besten mit der Fehlerbehandlung macht, weil teilweise der Server abstürzt, wenn ein Client disconnected etc.
Und dann natürlich noch die Frage, warum ein paar Aufträge bearbeitet werden und danach nichts mehr beim Server ankommt...

Ich hab einfach mal das gesamte Projekt in den Anhang gepackt.
Ach ja, bis jetzt ist das alles nur ein Testprojekt; das eigentliche Rechnen macht der TRenderThread in der Methode Execute(), da wird einfach ein Fraktal berechnet.

hier nochmal der Source der "Kommunikationsroutinen":

Delphi-Quellcode:
function SendData(ASocket: TCustomWinsocket; AData: Pointer; ASize: Integer;
  ATimeOut: Integer): Boolean;
  var send, tmp: Integer;
      time: Cardinal;
      PB: PByteArray;
  begin
  Result := False;
  if not ASocket.Connected then
    Exit;

  send := 0;
  time := GetTickCount;
  PB := AData;
  while send < ASize do
    begin
    tmp := ASocket.SendBuf(PB^[send], ASize-send);
    if tmp <> -1 then
      begin
      send := send + tmp;
      time := GetTickCount;
      end
    else
      if GetTickCount - time >= ATimeOut then
        Exit;
    if send <> ASize then
      Sleep(10);
    end;
  Result := True;
  end;

function ReceiveData(ASocket: TCustomWinsocket; AData: Pointer; ASize: Integer;
  ATimeOut: Integer): Boolean;
  var rec, tmp: Integer;
      time: Cardinal;
      PB: PByteArray;
  begin
  Result := False;
  if not ASocket.Connected then
    Exit;

  rec := 0;
  time := GetTickCount;
  PB := AData;
  while rec < ASize do
    begin
    tmp := ASocket.ReceiveBuf(PB^[rec], ASize - rec);
    if tmp <> -1 then
      begin
      rec := rec + tmp;
      time := GetTickCount;
      end
    else
      if GetTickCount - time >= ATimeOut then
        Exit;
    if rec <> ASize then
      Sleep(10);
    end;
  Result := True;
  end;

function ReceiveCommand(ASocket: TCustomWinSocket): string;
  var Sig: string;
      CommandLength: Byte;
      PB: PByteArray;
  begin
  Result := '';
  if ASocket.ReceiveLength < 4 then
    Exit;

  SetLength(Sig, 3);
  ReceiveData(ASocket, @Sig[1], 3);
  ReceiveData(ASocket, @CommandLength, 1);
  if Sig <> 'lrt' then
    Exit;

  SetLength(Result, CommandLength);
  ReceiveData(ASocket, @Result[1], CommandLength); {}
  end;

procedure SendCommand(ASocket: TCustomWinSocket; ACommand: string; AData: Pointer; ASize: Integer);
  var Data: string;
      l: Integer;
  begin
  Data := 'lrt' + Chr(Length(ACommand)) + ACommand;
  SendData(ASocket, @Data[1], Length(Data));
  if AData <> nil then
    SendData(ASocket, AData, ASize);
  end;
Ich bin für jede Hilfe dankbar.

thomasdrewermann 19. Jul 2006 01:10

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Hi,

ich würde der Einfachheit halbe für die Kommandos die Ereignisse Client/Server Read und Client/Server Write benutzen. Dort löst das Event immer aus, wenn er Zeichen empfängt. Der empfangene String wird dann auch direkt übergeben. Versenden auf Server-Seite geht dann mit serversocket1.Socket[nummer des verbundenen client beginnt bei client 1 mit 0].SendText, auf Client-Seite geht es mit clientsocket1.SendText weil er ja immer nur eine Verbindung hat.

Man muss nur darauf achten die empfangenen Daten sauber zu trennen, denn kruz hinter einander gesendete Zeichenketten werden manchmal als ein Event übergeben.

Hoffe zu helfen.

Gruß
Thomas

Muetze1 19. Jul 2006 09:09

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Zitat:

Zitat von thomasdrewermann
ich würde der Einfachheit halbe für die Kommandos die Ereignisse Client/Server Read und Client/Server Write benutzen.

Macht er so. Wo siehst du was anderes?

Zitat:

Zitat von thomasdrewermann
Dort löst das Event immer aus, wenn er Zeichen empfängt. Der empfangene String wird dann auch direkt übergeben.

Ist mir neu - wo wird denn da ein String übergeben? Du bekommst Sender übergeben und die TCustomWinSocket Instanz welche das Ereignis auslöst, aber einen String? Das wäre doch fatal wenn sich der Socket rausnehmen würde zu behaupten, ich will einen String haben. Der Socket hat gefälligst Daten zu übertragen und sich nicht anschicken zu vermuten was ich haben will - also String, ein Byte oder ein Block binäre Daten...

Zitat:

Zitat von thomasdrewermann
Versenden auf Server-Seite geht dann mit serversocket1.Socket[nummer des verbundenen client beginnt bei client 1 mit 0].SendText, auf Client-Seite geht es mit clientsocket1.SendText weil er ja immer nur eine Verbindung hat.

Warum? Er antwortet direkt im OnClientRead auf die empfangenen Packete und nutzt somit die übergebene TCustomWinSocket Instanz - und die findest du auch an den von dir genannten Orten wieder. Aber wo man sie bezieht ist Schnuppe - BlackJack's Weg ist genauso machbar und stellt kein Unterschied dar.

Zitat:

Zitat von thomasdrewermann
Man muss nur darauf achten die empfangenen Daten sauber zu trennen, denn kruz hinter einander gesendete Zeichenketten werden manchmal als ein Event übergeben.

... oder mehrere Events bis ein Datenteil empfangen wurde. Aber selbst darauf achtet er in seinem Code.

BlackJack 19. Jul 2006 12:09

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Zitat:

Zitat von Muetze1
Zitat:

Zitat von thomasdrewermann
Man muss nur darauf achten die empfangenen Daten sauber zu trennen, denn kruz hinter einander gesendete Zeichenketten werden manchmal als ein Event übergeben.

... oder mehrere Events bis ein Datenteil empfangen wurde. Aber selbst darauf achtet er in seinem Code.

Wie ist das denn, wenn ich im OnRead-Event sagen wir 50 byte gesendet bekomme (das kann ich doch über Socket.ReceiveLength erfahren, oder?), aber nur 30 Bytes über Socket.ReceiveBuffer aus dem Socket auslese. wenn dann wieder ein OnRead-Event auftritt, stehen dann "vorne im Socket" noch die restlichen 20 Byte vom vorherigen Event?

Oder umgekehrt, wenn ich 20 bytes im OnRead bekomme, aber 50 bytes aus dem Socket auslesen will, und während des Auslesens (also während ich noch auf die restlichen 30 byte warte) wird ein weiterer OnRead-Event ausgelöst. kann es dann sein dass der Event mit einem "leeren" Socket ausgeführt wird, weil ich die zugehörigen 30 bytes ja schon ausgelesen habe? weil das kommt bei mir auch manchmal vor, dass OnRead ausgeführt wird, aber Socket.ReceiveLength = 0 ist.

und ich weiss nicht genau wie ich das Onwrite benutzen soll (OnRead benutz ich ja schon). wird dieser Event nicht immer dann ausgelöst, wenn ich was mit socket.SendText/Buffer sende?

und ob ich jetzt SendText oder SendBuffer benutze sollte doch letztendlich egal sein, oder? nur dass man beim ReceiveBuffer noch angeben kann, wie viele Bytes er auslesen soll (und das ist ja wohl wichtig, wenn ich eben nicht wissen kann, ob die Nachrichten "vermischt" ankommen).

Muetze1 19. Jul 2006 12:27

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Zitat:

Zitat von BlackJack
Wie ist das denn, wenn ich im OnRead-Event sagen wir 50 byte gesendet bekomme (das kann ich doch über Socket.ReceiveLength erfahren, oder?), aber nur 30 Bytes über Socket.ReceiveBuffer aus dem Socket auslese. wenn dann wieder ein OnRead-Event auftritt, stehen dann "vorne im Socket" noch die restlichen 20 Byte vom vorherigen Event?

Ja.

Zitat:

Zitat von BlackJack
Oder umgekehrt, wenn ich 20 bytes im OnRead bekomme, aber 50 bytes aus dem Socket auslesen will, und während des Auslesens (also während ich noch auf die restlichen 30 byte warte) wird ein weiterer OnRead-Event ausgelöst. kann es dann sein dass der Event mit einem "leeren" Socket ausgeführt wird, weil ich die zugehörigen 30 bytes ja schon ausgelesen habe? weil das kommt bei mir auch manchmal vor, dass OnRead ausgeführt wird, aber Socket.ReceiveLength = 0 ist.

Ja. Da dein Code wartet bis die Receivelength stimmt (polling) aber der Socket mit Ereignisssteuerung arbeitet, teilt er dir durch erneutes aufrufen des OnRead mit. Da liegt auch dein Problem begraben. Dieser Aufruf wird vom Thread des Sockets ausgelöst und wird im Haupt VCL Thread Synchronisiert. Dieser hängt im Normalfall in deinem OnRead, weshalb er nicht zu Zuge kommt. Da du aber ein Sleep() drinne hast, gibst du Rechenzeit ab - u.a. an den VCL Thread, der dann dein OnRead erneut auslöst. Deine OnRead Methode wiederrum ist aber nicht reentrant ausgelegt und es kommt zu dem Problem wie von dir beschrieben.

Zitat:

Zitat von BlackJack
und ich weiss nicht genau wie ich das Onwrite benutzen soll (OnRead benutz ich ja schon). wird dieser Event nicht immer dann ausgelöst, wenn ich was mit socket.SendText/Buffer sende?

Vom Namen her schon, klar - aber im NonBlocking Mode der Sockets (d.h. sie benutzen einen Thread), wird dieses Event soweit nicht ausgelöst. Ich habe dieses Event bisher auch noch nie gebraucht.

Zitat:

Zitat von BlackJack
und ob ich jetzt SendText oder SendBuffer benutze sollte doch letztendlich egal sein, oder? nur dass man beim ReceiveBuffer noch angeben kann, wie viele Bytes er auslesen soll (und das ist ja wohl wichtig, wenn ich eben nicht wissen kann, ob die Nachrichten "vermischt" ankommen).

Der Buffer des Sockets ist es wurscht welche Daten in ihm liegen. Es ist ihm auch egal wie sie hineinkommen. SendBuf und SendText sind nur zwei Methoden für unterschiedliche Datentypen und somit nicht anders von der Funktionalität. Bei ReceiveText und ReceiveBuf() ist es entsprechend.

Die Sockets haben einen kleinen und begrenzten Buffer. Daher ist es nicht ratsam wissentlich Daten in einem OnRead nicht komplett auszulesen und zu warten bis die benötigte Menge an Daten empfangen ist. Es empfiehlt sich lieber einen Buffer selber an zu legen, alle Daten vom Socket in den Buffer zu schreiben (bzw. anzuhängen) und dann von vorne den Buffer durchgehen, interpretieren und schauen ob man genug empfangen hat. Dieser Teil kann immer nach einem erfolgtem OnRead ausgeführt werden. Nach erfolgreicher Interpretation einfach den Teil vorne vom Buffer entfernen. Ich habe dazu immer einen TMemoryStream verwendet und es klappte soweit alles recht gut. Beim Server muss man dann natürlich einen MemoryStream pro Client vorhalten. Ein grundlegendes Beispiel dazu könnte man sich in dem Chat auf meiner HP anschauen.

BlackJack 19. Jul 2006 12:53

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Zitat:

Zitat von Muetze1
Die Sockets haben einen kleinen und begrenzten Buffer. Daher ist es nicht ratsam wissentlich Daten in einem OnRead nicht komplett auszulesen und zu warten bis die benötigte Menge an Daten empfangen ist. Es empfiehlt sich lieber einen Buffer selber an zu legen, alle Daten vom Socket in den Buffer zu schreiben (bzw. anzuhängen) und dann von vorne den Buffer durchgehen, interpretieren und schauen ob man genug empfangen hat. Dieser Teil kann immer nach einem erfolgtem OnRead ausgeführt werden. Nach erfolgreicher Interpretation einfach den Teil vorne vom Buffer entfernen. Ich habe dazu immer einen TMemoryStream verwendet und es klappte soweit alles recht gut. Beim Server muss man dann natürlich einen MemoryStream pro Client vorhalten. Ein grundlegendes Beispiel dazu könnte man sich in dem Chat auf meiner HP anschauen.

also quasi ne Warteschlange? jo ich glaube das ist ne gute idee, so werde ich das mal versuchen. :-D
aber dann kann ich mir ja auch die eigene Methode zum Empfangen (ReceiveData) sparen, oder? weil wenn ich im OnRead einfach mit ReceiveText auslese, dann gibt er mit doch automatisch alles zurück, was der Socket grade vorliegen hat, und das kann dann einfach an die Warteschleife anhängt werden.
und ist damit dann nicht auch automatisch das Thread-Problem, das du beschrieben hast, gelöst?

Zitat:

Zitat von Muetze1
Ein grundlegendes Beispiel dazu könnte man sich in dem Chat auf meiner HP anschauen.

Ich möchte es aber vorher gerne alleine hinbekommen ;)

edit:
ach ja was haltet ihr von folgendem "Protkoll" für den austausch von Nachrichten/daten:
"lrt" ; 1 Byte für die Länge des Kommandos ; Kommandostring ; 4 Bytes für die Länge der eventuell folgenden Daten.

Muetze1 19. Jul 2006 13:45

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Zitat:

Zitat von BlackJack
also quasi ne Warteschlange? jo ich glaube das ist ne gute idee, so werde ich das mal versuchen. :-D

Joa, genau. Die nimmt alles auf was ankommt und immer wenn was hinzukommt, kannst du ja anhand deines Protokolls nachschauen ob du alles hast oder halt noch weiter warten musst.

Zitat:

Zitat von BlackJack
aber dann kann ich mir ja auch die eigene Methode zum Empfangen (ReceiveData) sparen, oder?

Ja, die hättest du so oder so extra bauen können und eigentlich auch direkt in die jeweils zugewiesene Methode. Vor allem nun hast du auf der Serverseite die Verwaltung der MemoryStreams pro Client noch zusätzlich (Tipp: Schau dir die Eigenschaft Data der TCustomWinSockets an).

Zitat:

Zitat von BlackJack
weil wenn ich im OnRead einfach mit ReceiveText auslese, dann gibt er mit doch automatisch alles zurück, was der Socket grade vorliegen hat, und das kann dann einfach an die Warteschleife anhängt werden.

Grundlegend richtig, aber in den Umsetzung zweifelhaft, da du mit TJob einen Record überträgst und somit würde dein String bei einem enthaltenen Nullbyte enden. Daher: Übertragung vom Socket in den TMemoryStream am besten immer mit ReceiveBuff und WriteBuffer. Andere Möglichkeit die mir hier gerade dabei einfällt:

Delphi-Quellcode:
procedure OnReceive:
begin
  MemoryStream.Position := MemoryStream.Size;
  MemoryStream.Size := MemoryStream.Size + Socket.ReceiveLength;

  Socket.ReceiveBuf(MemoryStream.Memory^, Socket.ReceiveLength);
End;
Gerade eingefallen - so spart man sich den Zwischenpuffer und das doppelte kopieren.

Zitat:

Zitat von BlackJack
und ist damit dann nicht auch automatisch das Thread-Problem, das du beschrieben hast, gelöst?

Jupp!

Zitat:

Zitat von BlackJack
edit:
ach ja was haltet ihr von folgendem "Protkoll" für den austausch von Nachrichten/daten:
"lrt" ; 1 Byte für die Länge des Kommandos ; Kommandostring ; 4 Bytes für die Länge der eventuell folgenden Daten.

Wie wäre es einfach nach der Kennung (die du später zum neu-synchronisieren verwenden kannst) 4 Bytes zu senden mit der Gesamtlänge? Dann könnte nämlich Server sowie Client bei unbekannten Kommandos diese überspringen - weil er zwar nicht weiss wie er sie handeln kann, aber überspringen kann er sie, da er ihre Gesamtlänge kennt.

"lrt"; 4 Bytes Gesamtlänge; 1 Byte Kommandolänge; Kommando; <abhängig vom Kommando>4 Byte Datenlänge; Daten</abhängig vom Kommando>

BlackJack 19. Jul 2006 14:22

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Zitat:

Zitat von Muetze1
(Tipp: Schau dir die Eigenschaft Data der TCustomWinSockets an).

hmm so wie ich das in der hilfe verstehe zeigt Data auf einen Block, der Infos zu der jeweiligen Socketverbindung speichert. allerdings steht in der Delphi-hilfe sonst nicht viel dazu, wo kann man da denn mehr erfahren?

Zitat:

Zitat von Muetze1
Andere Möglichkeit die mir hier gerade dabei einfällt:

Delphi-Quellcode:
procedure OnReceive:
begin
  MemoryStream.Position := MemoryStream.Size;
  MemoryStream.Size := MemoryStream.Size + Socket.ReceiveLength;

  Socket.ReceiveBuf(MemoryStream.Memory^, Socket.ReceiveLength);
End;

solle das dann nicht so aussehen:
Delphi-Quellcode:
Socket.ReceiveBuf(Pointer(Integer(MemoryStream.Memory) + OldSize)^, Socket.ReceiveLength);
weil so wie ich das verstanden habe zeigt Memory auf den Anfang der Daten, aber ich will ja ans Ende anhängen.


Zitat:

Zitat von Muetze1
Wie wäre es einfach nach der Kennung (die du später zum neu-synchronisieren verwenden kannst) 4 Bytes zu senden mit der Gesamtlänge? Dann könnte nämlich Server sowie Client bei unbekannten Kommandos diese überspringen - weil er zwar nicht weiss wie er sie handeln kann, aber überspringen kann er sie, da er ihre Gesamtlänge kennt.

dann müssten aber auch wieder die Methoden zum Auslesen aus dem MemoryStream bescheid wissen, welche Kommandos es gibt und welche falsch sind. Ich wollte es eigentlich so machen, dass ich ne Funktion hab, die das Kommando ausliest (vorher Kennung checken etc) und die eventuell folgenden Daten mit zurückgibt. und die aufrufende Methode bekommt dann halt das Kommando und muss selber entscheiden, ob sie was damit anfangen kann.

und kann man das so machen dass nach dem Auslesen aus dem MemoryStream alles rigoros relöscht wird, was nicht mit "lrt" beginnt? weil sonst pack ich mir den MemoryStream ja eventuell immer voller aber lese nie was draus aus.
(apropos: wie löscht man am schlauesten die ersten n bytes aus dem MemoryStream, ohne die gesamten restlichen Daten kopieren zu müssen?)

Muetze1 19. Jul 2006 14:35

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Zitat:

Zitat von BlackJack
Zitat:

Zitat von Muetze1
(Tipp: Schau dir die Eigenschaft Data der TCustomWinSockets an).

hmm so wie ich das in der hilfe verstehe zeigt Data auf einen Block, der Infos zu der jeweiligen Socketverbindung speichert. allerdings steht in der Delphi-hilfe sonst nicht viel dazu, wo kann man da denn mehr erfahren?

Ist genauso wie die Data Eigenschaft der TreeNodes oder die Tag Eigenschaft der Komponenten eine ungenutzte Eigenschaft die mitgeführt wird. Du kannst die Daten selber belegen. Somit kannst du im ClientConnect einen TMemoryStream anlegen und dessen Instanz in der Data Eigenschaft des Sockets vermerken und hast ihn somit immer sofort zur Verfügung.

Zitat:

Zitat von BlackJack
solle das dann nicht so aussehen:
Delphi-Quellcode:
Socket.ReceiveBuf(Pointer(Integer(MemoryStream.Memory) + OldSize)^, Socket.ReceiveLength);
weil so wie ich das verstanden habe zeigt Memory auf den Anfang der Daten, aber ich will ja ans Ende anhängen.

Ja, du hast vollkommen Recht, ich ging in meinem jugendlichen Leichtsinn fälschlicherweise davon aus, dass er Memory anpasst, abhängig von Position, aber dem ist nicht so.

Zitat:

Zitat von BlackJack
dann müssten aber auch wieder die Methoden zum Auslesen aus dem MemoryStream bescheid wissen, welche Kommandos es gibt und welche falsch sind. Ich wollte es eigentlich so machen, dass ich ne Funktion hab, die das Kommando ausliest (vorher Kennung checken etc) und die eventuell folgenden Daten mit zurückgibt. und die aufrufende Methode bekommt dann halt das Kommando und muss selber entscheiden, ob sie was damit anfangen kann.

Warum? Die Methode kann das Kommando und den Datenblock als Pointer auslesen und zurück geben. Wenn es kein Datenblock gibt, dann gibt es ein Nil zurück. Ob es einen Datenblock gibt, erkennt die Funktion unabhängig davon welches Kommando es ist, wenn die Gesamtlänge grösser als die Kommandolänge ist (plus 1, für das Byte der Kommandolänge). Ob das Kommando nun bekannt ist, das kannst du auch ausserhalb regeln und deine Funktion kannst du so schreiben - ohne das sie näheres Wissen.

Zitat:

Zitat von BlackJack
und kann man das so machen dass nach dem Auslesen aus dem MemoryStream alles rigoros relöscht wird, was nicht mit "lrt" beginnt?

Wenn du am Anfang einen Block hast, der nicht mit "lrt" beginnt, dann wurde zuviel oder zu wenig gesendet/ausgelesen. Daher müsstest du neu synchronisieren - also so lange auslesen bis du ein "lrt" findest. Aber rigeros löschen nicht, da du schon wieder Teile des nachfolgenden Blockes in dem MemoryStream haben kannst.

Zitat:

Zitat von BlackJack
(apropos: wie löscht man am schlauesten die ersten n bytes aus dem MemoryStream, ohne die gesamten restlichen Daten kopieren zu müssen?)

Kenne ich keine Methode, daher CopyFrom() und die Size Eigenschaft setzen.

BlackJack 19. Jul 2006 15:19

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Zitat:

Zitat von Muetze1
Ist genauso wie die Data Eigenschaft der TreeNodes oder die Tag Eigenschaft der Komponenten eine ungenutzte Eigenschaft die mitgeführt wird. Du kannst die Daten selber belegen. Somit kannst du im ClientConnect einen TMemoryStream anlegen und dessen Instanz in der Data Eigenschaft des Sockets vermerken und hast ihn somit immer sofort zur Verfügung.

jo das ist mal ne gute idee. :thumb:

Zitat:

Zitat von Muetze1
Warum? Die Methode kann das Kommando und den Datenblock als Pointer auslesen und zurück geben. Wenn es kein Datenblock gibt, dann gibt es ein Nil zurück. Ob es einen Datenblock gibt, erkennt die Funktion unabhängig davon welches Kommando es ist, wenn die Gesamtlänge grösser als die Kommandolänge ist (plus 1, für das Byte der Kommandolänge). Ob das Kommando nun bekannt ist, das kannst du auch ausserhalb regeln und deine Funktion kannst du so schreiben - ohne das sie näheres Wissen.

naja dann ist das ja eigentlich das gleiche wie ich es bisher auch vorhabe. wenn es keinen Datenblock gibt, dann wird einfach 0 in die Datenblocklänge geschrieben und gut ist. da überträgt man sogar genau die gleiche anzahl an bytes ;)


Zitat:

Zitat von Muetze1
Wenn du am Anfang einen Block hast, der nicht mit "lrt" beginnt, dann wurde zuviel oder zu wenig gesendet/ausgelesen. Daher müsstest du neu synchronisieren - also so lange auslesen bis du ein "lrt" findest. Aber rigeros löschen nicht, da du schon wieder Teile des nachfolgenden Blockes in dem MemoryStream haben kannst.

das zuviel/zuwenig ausgelesen wurde, kann ja eigentlich gar nicht vorkommen; ich lese ja erst dann aus dem MemoryStream aus, wenn alle Daten angekommen sind, und lösche die dann direkt aus dem Stream raus.
und zuviel oder zuwenig gesendet werden kann ja eigentlich auch nicht, dafür wird ja die Datenlänge übermittelt.
durch das weglöschen bis zum nächsten "lrt" wolle ich eigentlich verhindern, dass nicht die gesamte Warteschlange ins stocken gerät, wenn mal z.b. irgendein anderes programm was zu meinem Server hinschickt. ich würde mal sagen, wer sich nicht ans protokoll hält, ist selber schuld, oder? ;)

Zitat:

Zitat von Muetze1
Kenne ich keine Methode, daher CopyFrom() und die Size Eigenschaft setzen.

wenn ich Dest.CopyFrom(Source) mache, wie ist das dann mit den Positionen, von denen / an die kopiert wird? die Delphi-Hilfe ist da nicht ganz eindeutig....

Muetze1 19. Jul 2006 15:29

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
CopyFrom(Stream, Size);

Folgendes: Wenn Size = 0, dann kopiert er alles vom anderen Stream. D.h. er setzt Stream.Position auf 0 und kopiert alles. Wenn du aber in Size etwas grösser als 0 angibst, dann kopiert er Size Bytes von Stream ab der Stream.Position.

BlackJack 19. Jul 2006 15:32

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Zitat:

Zitat von Muetze1
CopyFrom(Stream, Size);

Folgendes: Wenn Size = 0, dann kopiert er alles vom anderen Stream. D.h. er setzt Stream.Position auf 0 und kopiert alles. Wenn du aber in Size etwas grösser als 0 angibst, dann kopiert er Size Bytes von Stream ab der Stream.Position.

und genau das war meine Frage: wenn ich Dest.CopyFrom(Source, Size) mache, dann kopiert er Size Bytes aus Source nach Dest. aber wohin nach Dest? nach Position = 0?

Muetze1 19. Jul 2006 15:35

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Zitat:

Zitat von BlackJack
und genau das war meine Frage: wenn ich Dest.CopyFrom(Source, Size) mache, dann kopiert er Size Bytes aus Source nach Dest. aber wohin nach Dest? nach Position = 0?

Ich dachte die Frage bezog sich auf die Quelle. Ziel ist immer die aktuelle Position im Stream.

BlackJack 19. Jul 2006 15:48

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
ok, aber dann bleibt mir ja keine andere Wahl als mit nem temporären MemoryStream arbeiten und ich kann nicht irgendwas wie fStream.CopyFrom(fStream, xxx) machen. aber gut ich denke jetzt hab ich erstmal genug Ideen um weiter proggen zu können.
Besten Dank :-D

BlackJack 19. Jul 2006 23:24

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ok dann kommen jetzt hier mal die Resultate, die ich mit den Tipps aus dem Thread hier erstellt habe. Über Netzwerk klappt das auch alles schon ganz gut, wenn ich allerdings übers Internet gehe schickt der Client nur ein paar mal Daten, und danach kommt nichts mehr - der Client bleibt allerdings anpingbar...
Hat dazu jemand ne Idee?

(etwa alle 30 sekunden werden alle Clients angepingt, also einfach mal geduldig auf den ping warten ;) ).

BlackJack 21. Jul 2006 17:32

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Liste der Anhänge anzeigen (Anzahl: 1)
also einen kleiner Fehler, wenn es im LAN "zu schnell" mit dem Nachrichtenaustausch wurde, hab ich ausmerzen können, allerdings bleibt weiterhin der Fehler beim benutzen einer Internetverbindung statt LAN... :(

inherited 21. Jul 2006 20:24

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Darf ich es wagen hier ein Wort namens 'Indy' in den Rum zu werfen?
Ich benutze sie sei t/d jeher und hatte nie eines der genannten Probleme

Muetze1 21. Jul 2006 21:59

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von inherited
Darf ich es wagen hier ein Wort namens 'Indy' in den Rum zu werfen?
Ich benutze sie sei t/d jeher und hatte nie eines der genannten Probleme

Die Probleme die hier sind, sind bei den Indys genauso möglich. Anstatt einfach so auf andere Dinge zu verweisen, was eine komplette Neuentwicklung bedeuten würden, könntest du ja dich an der Problemlösung beteiligen...

Hey, BlackJack! Mal eine Frage: Klappen die beiden EXE'n bei dir über's Internet? Bei mir habe ich nur LAN und ich habe schon lange gebraucht um die über LAN zum laufen zu bekommen. Ich habe ein paar Stellen im Code geändert und so läuft es nun stabil im LAN, daher die Frage. Teste es bitte mal und wenn es klappt, dann hänge ich mal die Quellen an und schreib mal kurz was zu den Änderungen und den Gründen - und die Vermutung die ich habe warum es nicht klappte.

MfG
Muetze1

BlackJack 22. Jul 2006 15:15

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
ne ich bekomm die nicht zum laufen, aber erstmal aus einem ganz anderen (sehr sehr stumpfen) grund:

und zwar ist in den Edits im Server ja 0.55 eingetragen, aber scheinbar will das StrToFloat im OnCreate ne Kommazahl als 0,55 haben. Deswegen gibt es im OnCreate ne Exception, irgendwas wird nicht createt und ich bekomm ne AV bei Adresse 0. :wall:

ich hab auch schon versucht die exe direkt zu "hacken" aber ich finde die Zeichenkette "0.55" nicht :wink:

könntest du also nochmal kompilieren und ein StringReplace mit reinbauen?

Muetze1 23. Jul 2006 00:23

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von BlackJack
ne ich bekomm die nicht zum laufen, aber erstmal aus einem ganz anderen (sehr sehr stumpfen) grund:

und zwar ist in den Edits im Server ja 0.55 eingetragen, aber scheinbar will das StrToFloat im OnCreate ne Kommazahl als 0,55 haben. Deswegen gibt es im OnCreate ne Exception, irgendwas wird nicht createt und ich bekomm ne AV bei Adresse 0. :wall:

ich hab auch schon versucht die exe direkt zu "hacken" aber ich finde die Zeichenkette "0.55" nicht :wink:

könntest du also nochmal kompilieren und ein StringReplace mit reinbauen?

Lol, ich hatte das Problem mit der Kommazahl mit deinen Quellen. Ich hatte das letzten schon mit einem MyFloatToStr() konvertiert, der es egal war...

Deine Ländereinstellungen sind dann aber komisch - aber klar, ich bau die nochmal...

BlackJack 23. Jul 2006 04:01

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
jo, super, jetzt geht es auch übers Internet, und das sogar mit einem Ping von 0-70 statt wie in meiner Version mit 500-700 :thumb:

und die ländereinstellungen muss ich dann wirklich bei mir wohl mal ändern, mich nervt das auch schon immer, Floats mit Komma eingeben zu müssen...

(wenn ich meine eigene INet-IP beim Client benutze, dann geht das doch de facto übers Internet, oder nicht?)

Muetze1 23. Jul 2006 14:13

Re: Client/Serververbindung arbeitet kurz und friert dann ei
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von BlackJack
(wenn ich meine eigene INet-IP beim Client benutze, dann geht das doch de facto übers Internet, oder nicht?)

Hängt von der Intelligenz deines NetzwerkStacks und deines Providers ab. Ich weiss es nicht.

Das vermutete Problem dabei war folgendes:
Wenn du gesendet hast, dann war das Problem, dass du ein Datenpacket mit zwei getrennten Befehlen in den Stream geschrieben hast. Damit war es möglich, dass durch die Beendigung des Threads, dieser genau zwischen diesen beiden Befehlen mit seinen berechneten Daten dazwischen gehauen hat.

Ich habe nun alles auf einheitliches SendStream umgestellt und sende immer den Stream erst ab, wenn er komplett ist. Damit weiss ich, dass dieser komplett auch so im Sendbuffer landet und nicht durch einen anderen zwischenzeitlichen Aufruf der Socket Methoden geteilt wird. Quellen im Anhang.


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:07 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz