Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Frage zu TClientSocket
IhopeonlyReader - Di 18.06.13 20:32
Titel: Frage zu TClientSocket
Guten Tag,
bei einem "direktBefehl" wo NUR Daten hingeschickt werden, ist mir etwas nerviges aufgefallen..
(Zum Server: Dieser empfängt die Daten und gibt sie in einem Memo aus (Testgründe) )
Bei folgendem Code, wurde NICHTS übertrage:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| var ClientT: TClientSocket; begin ClientT := TClientSocket.create( nil ); ClientT.Host := DieIP; ClientT.Port := 123456; ClientT.Open; ClientT.Socket.SendText( '1' ); ClientT.Socket.SendText( 'test' ); end; |
Am Server kommt nichts an!
Wenn ich wie im Beispiel Close und Free wegnehme, dann wird angezeigt, dass verbunden wurde (onClientWrite wird aufgerufen)
der 1 String (im Beispiel "4") wird nicht übergeben.. fehlt komplett...
Der string 'test' (über onclientread) kommt sogar VOR dem "verbinden" (clientwrite)
Wie muss ich wo warten?
Application.ProcessMessages und sleep bringen nichts !
IhopeonlyReader - Di 18.06.13 21:27
FinnO hat folgendes geschrieben : |
du hast auch nen Durchsatz...
|
Tut mir leid, verstehe ich nicht :oO:
Und dein tutorila ist zwar hilfreich, wusste ich aber schon...
Wo das Problem liegt, denke ich ja zu wissen.. aber wie kann man das ganze in 1 procedure machern? (Client erstellen, verbinden, text schicken, disconecten, Client freigeben) ohne entsprechendes Delay etc? oder wenigstens nur mit dem Minimum an notwendiger "Wartezeit"
FinnO - Di 18.06.13 21:34
Du musst das Ereignis OnConnect nutzen, ist das, was ich aus Narses' Tutorial mitnehme.
| Zitat: |
Delphi-Quelltext 1: 2: 3: 4: 5:
| procedure TForm1.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket); begin Log.Lines.Add('Verbunden mit '+ServerAdress.Text); end; | |
IhopeonlyReader - Di 18.06.13 22:09
Vielen Dank :)
So funktionierts
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| procedure TForm1.ClientTOnConnect(Sender: TObject; Socket: TCustomWinSocket); begin ClientT.Socket.SendText( Edit1.Text ); sleep( SizeOf(Edit1.Text) ); ClientT.Close; ClientT.Free; end;
procedure TForm1.Button1Click(Sender: TObject); begin ClientT := TClientSocket.create( nil ); ClientT.Host := 'localhost'; ClientT.Port := 12345; ClientT.OnConnect := ClientTOnConnect; ClientT.Open; end; |
Edit: die Variable muss doch nicht global deklariert werden :freu:
Dazu muss die Procedure zu abgeändert werden:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| procedure TForm1.ClientTOnConnect(Sender: TObject; Socket: TCustomWinSocket); begin TClientSocket(Sender).Socket.SendText( Edit1.Text ); sleep( SizeOf(Edit1.Text) ); TClientSocket(Sender).Close; TClientSocket(Sender).Free; end; |
Ich gehe davon aus, dass als Sender nur der "Auslöser" gemeint sein kann, und somit das TClientSocket
Nachtrag: Sleep ist unnötig, da ein String nur ein Zeiger auf ein Array of Char ist.. somit immer die größe von 4 hat. sleep(4) ist insg. unnötig
jaenicke - Di 18.06.13 22:25
Den Sender in einer eigenen Ereignisroutine freizugeben ist keine gute Idee. Meistens wird nach dem Aufruf deiner Ereignis-Prozedur noch auf die Komponente zugegriffen, und da die dann schon freigegeben ist, knallt das ggf. gewaltig. Wenn du Glück hast, wird nur Speicher an den Stellen gelesen und es passiert nichts, aber ein Fehler ist das trotzdem.
Aus solchen Sachen resultieren jedenfalls gerade bei größeren Programmen schwer zu findende Probleme, die sich ganz woanders äußern. Heißt: Beide Varianten sind äußerst bedenklich...
IhopeonlyReader - Di 18.06.13 22:41
kennst du bessere Vorschläge? wie z.B. das Close und free in einen Timer setzten.. nebenbei eine boolean variable deklarieren, die beim OnConnect auf True gesetzt wird.. der timer wird nur ausgeführt, wenn diese variable true ist...
das wäre noch unsauberer meiner Meinung nach.. aber "sicherer"
IhopeonlyReader - Mi 19.06.13 16:21
dazu noch eine Frage, wann wird der Client (denn endlich) connected?
Wenn man eine Schleife macht wo man Clients erstellt und verbindet, dann verbindet er den 1 Client erst, wenn die schleife durch ist...
>M@steR< - Mi 19.06.13 16:42
Gelöscht
IhopeonlyReader - Mi 19.06.13 18:25
ok, also muss ich das ganze in ein extra thread einlagern.. schade
IhopeonlyReader - Mi 19.06.13 20:46
Für alle die es interessiert ;)
Ich habe es nun umgesetzt, dass
- ein Client erstellt wird
- Host, IP gesetzt werden
- verbunden wird
- ein String gesendet wird
- getrennt wird
- der Client freigegeben wird
und das alles in einer While-Schleife !
Hier der Code ;)
Thread:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68:
| unit uTSent; interface uses Classes, ScktComp; type TSent = class(TThread) private DerClient: TClientSocket; ZuSenden: String; fFertig, fGeklappt: Boolean; procedure ClientTOnConnect(Sender: TObject; Socket: TCustomWinSocket); procedure ClientTOnError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); protected procedure Execute; override; public property Fertig: Boolean read fFertig; property Geklappt: Boolean read fGeklappt; constructor create( IP: String; Port: Word; ZuSendenderText: String ); end;
implementation
procedure TSent.ClientTOnConnect(Sender: TObject; Socket: TCustomWinSocket); begin try Socket.SendText( ZuSenden ); except fGeklappt := False; end; DerClient.Close; DerClient.Free; fFertig := True; end;
procedure TSent.ClientTOnError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin ErrorCode := 0; fGeklappt := False; DerClient.Close; DerClient.Free; fFertig := True; end;
constructor TSent.create( IP: String; Port: Word; ZuSendenderText: String ); begin inherited create( true ); fFertig := False; fGeklappt := True; DerClient := TClientSocket.Create( nil ); DerClient.Host := IP; DerClient.Address := IP; DerClient.Port := Port; ZuSenden := ZuSendenderText; DerClient.OnConnect := ClientTOnConnect; DerClient.OnError := ClientTOnError; DerClient.Open; end;
procedure TSent.Execute; begin end;
end. |
Hier gibt es den Super-seltenen-Sonderfall, dass beim erstellen des Threads es völlig egal ist, ob er suspended ist oder nicht !
Ein Beispiel der Nutzung
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure TForm1.Button1Click(Sender: TObject); var EThread: TSent; begin EThread := TSent.create( 'localhost', StrToInt(EPort.Text), ENachricht.Text ); while not EThread.Fertig do begin Application.ProcessMessages; end; if EThread.Geklappt then Showmessage( 'Fertig und Geklappt' ) else Showmessage( 'Fertig, aber Fail' ); EThread.Free; end; |
Nach der ersten Ausführung werden 1416 KB mehr benötigt, ich weiß leider nicht warum.. aber es wird nach mehrfacher Ausführung nicht mehr ! somit wird nicht vergessen irgendetwas freizugeben...
jaenicke - Mi 19.06.13 20:57
Dass du da gar keinen Thread wirklich benutzt, ist dir aber schon klar, oder? Im Thread wird ausschließlich das ausgeführt was in OnExecute steht. Du kannst die Klasse genausogut bzw. sinnvoller gar nicht erst von TThread ableiten.
IhopeonlyReader - Mi 19.06.13 21:12
nein, habe ich ausprobiert !
die proceduren ClientTOnConnect und ClientTOnError werden, falls sie ausgelöst werden, im Thread ausgelöst !
jaenicke - Mi 19.06.13 21:27
Lass dir einfach mit GetCurrentThreadId die ID des aktuellen Threads ausgeben (einmal in OnConnect und einmal in deinem Hauptthread) oder schau in die Liste der Threads in Delphi.
Davon abgesehen:
Nimm einfach das (TThread) hinter class weg und du wirst sehen, dass es 1:1 genauso funktioniert...
IhopeonlyReader - Mi 19.06.13 21:33
tatsächlich.. dass es funktioniert liegt am Application.ProcessMessages;
mhhh.. aber gibt es soetwas auch in "threads"? da gibt es ja keine application
Narses - Mi 19.06.13 22:53
Moin!
Lieber Gott, was tust du denn da nur immer wieder... :hair: Willst du Reifenhändler werden oder warum erfindest du die Dinger immer wieder neu?! :rofl:
Wenn du einen synchronen Socket haben willst, dann stell doch einfach die Eigenschaft .ClientType auf ctBlocking und gut ist, dann gibt´s auch keine Ereignisse mehr. Dann aber die try-finally-Blöcke nicht vergesen, weil dann gibt´s auch kein OnError mehr, sondern Exceptions. :idea:
cu
Narses
FinnO - Mi 19.06.13 23:24
Endlich mal der Experte :) :flehan:
IhopeonlyReader - Fr 21.06.13 15:41
Narses hat folgendes geschrieben : |
Eigenschaft .ClientType auf ctBlocking und gut ist, dann gibt´s auch keine Ereignisse mehr. Dann aber die try-finally-Blöcke nicht vergesen, weil dann gibt´s auch kein OnError mehr, sondern Exceptions. :idea:
|
das war das was ich suchte (ClientType ctBlocking) DANKE !.. dazu jetzt noch eine frage..
was ist der unterschied zwischen onconnect und dem code NACH dem open im selben try-blcok?
Beispiel:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| machwas1
try Derclient.open; machwas2; finally if derclient.socket.connected then derclient.close; end; |
es macht doch jetzt kein unterschied ob ich machwas in onconnect oder nach dem open aufrufe oder?
jaenicke - Fr 21.06.13 16:07
Wenn du den Socket auf blockierend gestellt hast, blockiert der bis die Operation (das Verbinden) abgeschlossen ist. Dann kannst du nach dem Connect auch etwas ausführen, das auf dem Verbindungszustand basiert und diesen prüft.
Hast du den Socket auf nicht blockierend, wartet der nicht, d.h. du kommst in dem Code nach dem Connect evtl. an bevor das Verbinden abgearbeitet ist. Dann ist der Socket da ggf. noch nicht connected. Dann musst du OnConnect nutzen.
IhopeonlyReader - Fr 21.06.13 23:59
Ja, ich meinte jetzt speziell bei ctblocking
jaenicke - Sa 22.06.13 10:00
Laut
Narses gibts dann die Ereignisse gar nicht mehr, selbst probiert habe ich das nicht:
Narses hat folgendes geschrieben : |
| dann stell doch einfach die Eigenschaft .ClientType auf ctBlocking und gut ist, dann gibt´s auch keine Ereignisse mehr. |
Sinn machen sie auf jeden Fall weniger bei Blocking, da du ja weißt, dass der Aufruf erst zurückkehrt, wenn alles erledigt ist.
IhopeonlyReader - Sa 22.06.13 12:50
Also bei mir wird das OnError nicht mehr aufgerufen.. Das OnConnect wird allerdings weiterhin ausgeführt.. (auf ctBlocking)
deshalb habe ich mich ja gewundert :D
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!