Autor |
Beitrag |
::micha::
Hält's aus hier
Beiträge: 8
|
Verfasst: Fr 15.02.08 14:02
Hallo,
ich habe ein Problem beim Lesen der Daten.
Das die Daten ordentlich gesendet und empfangen werden überprüfe ich mit einem Netzwerkmonitor.
Beim Lesen in der Methode IdTCPServerExecute kommt es allerdings für mich zu unverständlichen Dingen.
1. Versuch: AContext.Connection.IOHandler.ReadLn
bringt leider gar keinen String
2. Versuch: AContext.Connection.IOHandler.ReadString(9)
bring mir die daten, leider sind aber die Bytes teilweise in der Reihenfolge vertauscht
außerdem bringt es mir auch keine daten mehr, wenn ich zum Beipiel 565 Bytes auslesen will.
und wie gesagt, dass obwohl die Daten richtig im Netz umherschwirren
ich nutze Indy 10.1.5
ich hoffe ihr könnt mir weiterhelfen
gruß
Micha
Zuletzt bearbeitet von ::micha:: am Mo 18.02.08 14:12, insgesamt 1-mal bearbeitet
|
|
opfer.der.genauigkeit
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: Fr 15.02.08 16:21
Ich glaube 'n bissl Code wäre hilfreich.
_________________ Stellen Sie sich bitte Zirkusmusik vor.
|
|
::micha::
Hält's aus hier
Beiträge: 8
|
Verfasst: Mo 18.02.08 09:09
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure TForm1.IdTCPServerExecute(AContext: TIdContext); begin If Not AContext.Connection.IOHandler.Readable Then Exit; if bVersionLesen then begin self.Memo.Lines.Add(AContext.Connection.IOHandler.ReadString(9)); end; if bStatusabfrage then begin self.Memo.Lines.Add(AContext.Connection.IOHandler.ReadString(40)); end; if bWerkzeugdatenLesen then begin self.Memo.Lines.Add(AContext.Connection.IOHandler.ReadString(565)); end; end; |
hier nun wie gewünscht etwas code
gruß
Micha
Zuletzt bearbeitet von ::micha:: am Mo 18.02.08 09:25, insgesamt 1-mal bearbeitet
|
|
elundril
Beiträge: 3747
Erhaltene Danke: 123
Windows Vista, Ubuntu
Delphi 7 PE "Codename: Aurora", Eclipse Ganymede
|
Verfasst: Mo 18.02.08 09:14
verwende bitte die [code]- Tags.
also so:
[delphi]
{<--//Hier dein Code//-->}
[/delphi]
danke,
lg elundril
_________________ This Signature-Space is intentionally left blank.
Bei Beschwerden, bitte den Beschwerdebutton (gekennzeichnet mit PN) verwenden.
|
|
opfer.der.genauigkeit
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: Mo 18.02.08 14:30
Schonmal den Port gecheckt?
Vergessen den Server auf Active zu setzen?
Ich habe das mal versucht nachzustellen.
Client:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TForm1.FormCreate(Sender: TObject); begin IdTCPClient1.Host := '127.0.0.1'; IdTCPClient1.Port := 666; end;
procedure TForm1.Button1Click(Sender: TObject); begin IdTCPClient1.Connect; IdTCPClient1.Socket.WriteLn( Memo1.Lines.Text ); IdTCPClient1.Disconnect; end; |
Server:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure TForm2.FormCreate(Sender: TObject); begin IdTCPServer1.DefaultPort := 666; IdTCPServer1.Active := true; end;
procedure TForm2.IdTCPServer1Execute(AContext: TIdContext); begin Memo1.Lines.Add( AContext.Connection.IOHandler.ReadLn ); end; |
Der Code soll bitte nur zeigen, dass es geht, wie es geht und
erhebt keinen Anspruch auf ernsthafte Qualität.
_________________ Stellen Sie sich bitte Zirkusmusik vor.
|
|
::micha::
Hält's aus hier
Beiträge: 8
|
Verfasst: Mo 18.02.08 15:36
Port und Active ist ok!
es klappt ja auch beim lesen von nur 9 bytes aber bei 565 geht es nicht und bei Readln oder allData passiert nix.
wer kann mir helfen?
danke
Micha
|
|
opfer.der.genauigkeit
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: Mo 18.02.08 16:52
Wie sendest du deine Daten?
_________________ Stellen Sie sich bitte Zirkusmusik vor.
|
|
Xentar
Beiträge: 2077
Erhaltene Danke: 2
Win XP
Delphi 5 Ent., Delphi 2007 Prof
|
Verfasst: Mo 18.02.08 17:28
Ich weiß nicht, ob das bei Indy10 immer noch so ist, aber bei Indy9 hatte ich häufiger Probleme mit der Funktion Readable, da diese teilweise ein falsches Ergebnis lieferte. Vielleicht hab ich auch nur die Funktion falsch verwendet.
Hab das immer so gemacht, dass ich ein Read mit Timeout aufgerufen hab, und wenn der String = '' war, wurde eben nichts empfangen.
|
|
::micha::
Hält's aus hier
Beiträge: 8
|
Verfasst: Di 19.02.08 13:09
ich sende die Daten mit "WriteLn('')"
|
|
opfer.der.genauigkeit
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: Di 19.02.08 13:14
WriteLn? Hm... das erinnert mich an einen Code, den ich mal irgendwo hier im Forum gepostet habe...
ich glaube der verwendet ReadLn um die Daten zu empfangen...
_________________ Stellen Sie sich bitte Zirkusmusik vor.
|
|
::micha::
Hält's aus hier
Beiträge: 8
|
Verfasst: Di 19.02.08 14:43
was willst du mir damit sagen??
|
|
opfer.der.genauigkeit
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: Di 19.02.08 17:17
Wenn du eh über WriteLn schreibst, musst du dir nicht die Mühe machen und komplizierter lesen als nötig.
Bei ReadString musst du immer wissen, wieviele Daten im Eingang sind.
Wird ein zu Großer ReadCount angegeben, schlägt die Funktion fehl.
_________________ Stellen Sie sich bitte Zirkusmusik vor.
|
|
::micha::
Hält's aus hier
Beiträge: 8
|
Verfasst: Mi 20.02.08 08:42
wie schon im ersten posting geschrieben liefert ReadLn leider gar keine Ergebnis, mir wäre diese Funktion sicher die Liebste
|
|
opfer.der.genauigkeit
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: Mi 20.02.08 14:53
Auch nicht bei dem Code, den ich dir gepostet habe?
Ich habe das bei mir, lokal allerdings, getestet und es bestens funktioniert.
Sofern dein Code nicht Topsecret ist könntest du ihn ja mal komplett posten oder als Zip anhängen.
_________________ Stellen Sie sich bitte Zirkusmusik vor.
|
|
Quitzlinga
Beiträge: 60
Erhaltene Danke: 2
Win XP
Delphi 2007 Prof. Codegear Win32
|
Verfasst: Fr 22.02.08 10:51
Wie stellst Du die Länge fest, die Du liest ? Wenn es Du es z.B. so gemacht hast, das Du einen String mittels WriteLn sendest (z.B. WriteLn('12345678'); = 8 Zeichen) und dann einfach versuchst am Client eine bestimmte Anzahl Zeichen zu lesen (Das tut deine Funktion nämlich), so wird es vermutlich nicht klappen. Grund : WriteLn sendet zusätzlich zu Deinen Zeichen noch ein CRLF (Carriage Return Line Feed = 2 Zeichen), das sogenannte Terminatorzeichen bei INDY. So kann die Funktion ReadLn erkennen, wann ein kompletter Datenstring vorliegt und würde sonst solange warten, bis ein CRLF auftaucht. Ich vermute mal, das Du diese zusätzlichen Zeichen nicht berücksichtigst hast.
Aber eine weitere Frage : Wie stellst Du überhaupt fest, wieviel Zeichen du sendest ? Deine Server Execute Funktion hat zwar Verzweigungen aber wo stellst Du bVersion, bStatus etc ein ? Diese Information musst Du deinem Server ja auch irgentwie zur Verfügung stellen, sonst wird er ohne das obige Problem zu berücksichtigen in 1/3 der Fälle ohnehin die falsche Anzahl an Informationen lesen.
Ich rate Dir zu der Lösung von opfer.der.genauigkeit. Ohnehin wirst Du später sonst Probleme bekommen, wenn Du Deinen Code erweiterst, da Du ständig darauf achten musst, die richtige Anzahl an Informationen zu lesen.
[/user]
MfG
Quitzlinga
|
|
artelogic
Beiträge: 39
|
Verfasst: Sa 23.02.08 11:13
Ich schätze mal, du beachtest nicht, daß TIdTCPServer multithreaded ist. Dh, das Execute-Event läuft nicht im MainThread und sollte somit nicht auf VCL-Objekte (die nämlich nicht thread-safe sind) zugreifen, weil es sonst zu unvorhersehbaren und teilweise nicht reproduzierbaren Effekten kommt, wie du ja merkst.
|
|
opfer.der.genauigkeit
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: So 24.02.08 13:29
Nachdem ich das Thema des Oefteren antreffe, habe ich mir einen kurzen Einblick in die Indykomponenten gegönnt.
Meine Lösung ist mit Sicherheit nicht perfekt und einen Timer sollte man für soetwas auch garnicht verwenden , aber ich sehe das als Denkhilfe für Anfänger und da muss man nicht noch mit Threads antanzen.
Man erstelle ein Formular mit einer TIdTCPServer-Komponente und einem TMemo.
Man kopiere folgenden Code...
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:
| unit Unit2;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPServer;
type TForm2 = class(TForm) Memo1: TMemo; IdTCPServer1: TIdTCPServer; procedure IdTCPServer1Execute(AContext: TIdContext); procedure IdTCPServer1Connect(AContext: TIdContext); procedure IdTCPServer1Disconnect(AContext: TIdContext); procedure FormCreate(Sender: TObject); end;
var Form2: TForm2;
implementation
{$R *.dfm}
procedure TForm2.FormCreate(Sender: TObject); begin IdTCPServer1.DefaultPort := 666; IdTCPServer1.Active := true; end;
procedure TForm2.IdTCPServer1Connect(AContext: TIdContext); begin AContext.Connection.IOHandler.WriteLn( 'Hallo' ); Memo1.Lines.Add( 'Client connected' ); end;
procedure TForm2.IdTCPServer1Disconnect(AContext: TIdContext); begin Memo1.Lines.Add( 'Client disconnected' ); end;
procedure TForm2.IdTCPServer1Execute(AContext: TIdContext); var s: string; begin s := AContext.Connection.IOHandler.ReadLn;
if not ( s = '' ) then begin Memo1.Lines.Add( s ); AContext.Connection.IOHandler.WriteLn( 'Got message.' ); end; end;
end. |
... Server fertig.
Zum Client... Forumlar erstellen, TIdTCPClient-Komponente + TMemo + TButton + TTimer...
Der Code...
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:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, ExtCtrls;
type TForm1 = class(TForm) IdTCPClient1: TIdTCPClient; Memo1: TMemo; Button1: TButton; Timer1: TTimer; procedure Button1Click(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormCreate(Sender: TObject); end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject); begin IdTCPClient1.Host := '127.0.0.1'; IdTCPClient1.Port := 666; IdTCPClient1.Connect; end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin IdTCPClient1.Disconnect; end;
procedure TForm1.Timer1Timer(Sender: TObject); begin IdTCPClient1.IOHandler.CheckForDataOnSource( 5 );
if ( IdTCPClient1.IOHandler.InputBuffer.Size > 0 ) then begin Memo1.Lines.Add( IdTCPClient1.IOHandler.ReadLn ); end; end;
procedure TForm1.Button1Click(Sender: TObject); begin IdTCPClient1.IOHandler.WriteLn( Memo1.Text ); end;
end. |
So, fertig.
Noch ein paar Worte:
Für einen vernünftigen Chat reicht das nicht! Nein, auch einen TTimer sollte man an dieser Stelle nicht platzieren -> siehe Fiber oder Threads.
Wenn jemand weiß, ob es einen internen Thread gibt, der beim Empfang neuer Daten ein entsprechendes Event ausführt... immer her damit.
Des Weiteren sei angemerkt, dass das Execute vom Server sowohl beim Senden, also auch beim Empfangen von Daten aufgerufen wird. Das ist evtl. eine Randnotiz, die gerade Neulingen eine menge Verwirrung sparen kann.
Wünsche werden ignoriert, Kritik ist willkommen.
//Edit: Execute im Server ist nicht Threadsafe! (siehe ein Post weiter unten)
_________________ Stellen Sie sich bitte Zirkusmusik vor.
Zuletzt bearbeitet von opfer.der.genauigkeit am So 24.02.08 16:49, insgesamt 2-mal bearbeitet
|
|
artelogic
Beiträge: 39
|
Verfasst: So 24.02.08 14:37
|
|
opfer.der.genauigkeit
Beiträge: 754
Erhaltene Danke: 1
|
Verfasst: So 24.02.08 16:08
opfer.der.genauigkeit hat folgendes geschrieben: | Meine Lösung ist mit Sicherheit nicht perfekt und einen Timer sollte man für soetwas auch garnicht verwenden , aber ich sehe das als Denkhilfe für Anfänger und da muss man nicht noch mit Threads antanzen. |
Ich dachte damit hätte ich alles gesagt...
Allein einen Timer zu verwenden...
Ich würde nicht mal die Indy-Komponeten verwenden, wenn es ein ernsthaftes Projekt werden soll.
Aber ich mache mal 'n Edit oben.
_________________ Stellen Sie sich bitte Zirkusmusik vor.
|
|
artelogic
Beiträge: 39
|
Verfasst: So 24.02.08 18:07
sei mir nicht böse, aber ich versteh den denkansatz nicht. hier hat doch jemand ein konkretes problem gepostet, oder?
und ich schätze mal, der will sein problem gelöst wissen und nicht irgendein firlefanz gelaber hören. und sein problem ist, daß er aus einem anderen als dem MainThread auf VCL-Komponenten zugreift. und da kannste jetzt nicht einfach sagen, vergessen wir mal die threads und lösen das problem indem wir es ignorieren.
und ich weiß auch nicht, was gegen einen timer spricht, wenn es was zu timen gibt. und noch viel weniger weiß ich, was an den indy komponenten auszusetzen ist. die sind durchaus robust genug, um sie bei professionellen projekten einzusetzen.
|
|