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:
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:
Ich bin für jede Hilfe dankbar.
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; |
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 |
Re: Client/Serververbindung arbeitet kurz und friert dann ei
Zitat:
Zitat:
Zitat:
Zitat:
|
Re: Client/Serververbindung arbeitet kurz und friert dann ei
Zitat:
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). |
Re: Client/Serververbindung arbeitet kurz und friert dann ei
Zitat:
Zitat:
Zitat:
Zitat:
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. |
Re: Client/Serververbindung arbeitet kurz und friert dann ei
Zitat:
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:
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. |
Re: Client/Serververbindung arbeitet kurz und friert dann ei
Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
Gerade eingefallen - so spart man sich den Zwischenpuffer und das doppelte kopieren.
procedure OnReceive:
begin MemoryStream.Position := MemoryStream.Size; MemoryStream.Size := MemoryStream.Size + Socket.ReceiveLength; Socket.ReceiveBuf(MemoryStream.Memory^, Socket.ReceiveLength); End; Zitat:
Zitat:
"lrt"; 4 Bytes Gesamtlänge; 1 Byte Kommandolänge; Kommando; <abhängig vom Kommando>4 Byte Datenlänge; Daten</abhängig vom Kommando> |
Re: Client/Serververbindung arbeitet kurz und friert dann ei
Zitat:
Zitat:
Delphi-Quellcode:
weil so wie ich das verstanden habe zeigt Memory auf den Anfang der Daten, aber ich will ja ans Ende anhängen.
Socket.ReceiveBuf(Pointer(Integer(MemoryStream.Memory) + OldSize)^, Socket.ReceiveLength);
Zitat:
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?) |
Re: Client/Serververbindung arbeitet kurz und friert dann ei
Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
|
Re: Client/Serververbindung arbeitet kurz und friert dann ei
Zitat:
Zitat:
Zitat:
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:
|
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. |
Re: Client/Serververbindung arbeitet kurz und friert dann ei
Zitat:
|
Re: Client/Serververbindung arbeitet kurz und friert dann ei
Zitat:
|
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 |
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 ;) ). |
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... :(
|
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 |
Re: Client/Serververbindung arbeitet kurz und friert dann ei
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
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 |
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? |
Re: Client/Serververbindung arbeitet kurz und friert dann ei
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Deine Ländereinstellungen sind dann aber komisch - aber klar, ich bau die nochmal... |
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?) |
Re: Client/Serververbindung arbeitet kurz und friert dann ei
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
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