![]() |
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:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:42 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz