![]() |
[Indy 10] IRC-Client in eigenem thread auslagern
Guten Morgen allerseits,
ich habe mich leider schon ganz schön lange nicht mehr richtig mit multithreading beschäftigt, so bin ichs der materie ein wenig drausen, jetzt müsste ich jedoch einen IRC-Client, welcher zur Laufzeit im eigenem Thread laufen soll auf mein programm bringen... Das problem ist folgendes: Das erstellen vom Thread funktioniert an sicht und das joinen auch (aufm Server nachgeguckt), die Frage ist jedoch, wie "empfange" ich Daten, die der Server verschickt? Meine Bisherigen Zeilen:
Delphi-Quellcode:
Es ist noch nicht alles so, wie ichs am ende haben möchte, jedoch geht es im prinzip momentan eher nur um die procedure TIRC.Execute...
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, IDIRC, IDContext, StdCtrls; type TForm1 = class(TForm) Memo1: TMemo; procedure ReceiveIRC(ASender: TIdContext; const ANicknameFrom, AHost, ANicknameTo, AMessage: String); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; type TIRC = class(TThread) private FConnected : Boolean; public IRC : TIDIRC; Host : AnsiString; Port : Word; constructor Create(CreateSuspended:Boolean); procedure StartIRC(Channel,MyName : AnsiString); procedure Execute; override; destructor Free; end; var Form1: TForm1; IRC : TIRC; implementation {$R *.dfm} constructor TIRC.Create(CreateSuspended: Boolean); begin inherited Create(CreateSuspended); IRC := TIDIRC.Create(NIL); Host := 'myserver'; Port := 6667; end; procedure TIRC.StartIRC(Channel, MyName : AnsiString); begin IRC.Host := Host; IRC.Port := Port; IRC.Username := MyName; IRC.Realname := MyName; IRC.Nickname := MyName; IRC.OnPrivateMessage := Form1.ReceiveIRC; IRC.Connect; IRC.Join(Channel); FConnected := True; end; procedure TIRC.Execute; var ASender : TIDContext; ANick,AHost,ANickTo,AMessage : String; begin while (not Self.Terminated) do begin if (FConnected) and (IRC.Connected) then //Wie lese ich hier die Daten (/hole sie ab), wenn etwas ankommt, so, dass OnPrivateMessage aufgerufen wird? end; end; destructor TIRC.Free; begin try IRC.Free; except end; inherited Destroy; end; procedure TForm1.FormCreate(Sender: TObject); var Channel, MyName : AnsiString; begin IRC := TIRC.Create(false); Channel := 'channel'; MyName := 'User001'; IRC.StartIRC(Channel,MyName); end; procedure TForm1.FormDestroy(Sender: TObject); begin IRC.Free; end; procedure TForm1.ReceiveIRC(ASender: TIdContext; const ANicknameFrom: string; const AHost: string; const ANicknameTo: string; const AMessage: string); begin if AMessage <> '' then Memo1.Lines.Add(AMessage); end; Viele Grüße Sfaizst |
AW: [Indy 10] IRC-Client in eigenem thread auslagern
Laufen die Indys nicht schon von Haus aus in einem Thread? D.h. darum müsstest du dich gar nicht kümmern.
|
AW: [Indy 10] IRC-Client in eigenem thread auslagern
Hmm, das kann ich leider nicht genauer sagen, ich habe die komponente mal zur Laufzeit ohne extra Thread probiert und als der Server nicht erreichbar war (wlan abgeschmiert) hing die Form für 30 Sekunden, so gehe ich davon aus, dass es eben nicht im eigenem Thread läuft.
|
AW: [Indy 10] IRC-Client in eigenem thread auslagern
Hi,
die Server laufen in seperaten Threads für die jeweiligen Clients. Die Clients laufen ohne eigenen Thread, deshalb empfielt es sich die Client-Kommunikation in einen seperaten Thread auszulagern, wie Du es auch schon angefangen hast. Greetz Data P.S.: Ohnen Thread sollte man die TIdAntiFreeze Komponente auf die Form ziehen. |
AW: [Indy 10] IRC-Client in eigenem thread auslagern
Danke für die Info,
das Problem ist aber im eigentlichen, dass ich nicht weiß, wie ich die IRC Narichten abholen kann, bei sockets,... gibt es ja eine Procedure um eingegangene Narichten abzuholen, aber welche ist das beim IRC? Zitat:
Sfaizst |
AW: [Indy 10] IRC-Client in eigenem thread auslagern
hallo, ich habe inzwischen das Ding mit IDAntiFreeze probiert, das Resultat ist aber nicht wirklich zufriedenstellend, die Form hängt regelmäßig,...
Kann mir denn niemand sagen, wie ich die IRC Narichten im Thread abholen kann und somit dann OnPrivateMessage aufrufen kann? Grüßle |
AW: [Indy 10] IRC-Client in eigenem thread auslagern
Hi,
die IdIRC Komponente ist eine der wenigen die ich noch nicht benutzt/benötigt habe, allerdings kenne ich ansonsten recht gut mit den Indy-Komponenten aus. Dein Gedankengang mit dem Thread ist absolut richtig, allerdings solltest Du alle Events von TIdIRC(somit auch OnPrivateMessage) innerhalb des Threads behandeln und NICHT direkt an die Form verweisen. Für eine Interaktionen zwischen Thread(s) und VCL-Komponenten(auch Forms) ist die Syncronisation der Interaktion dringend zu Verwenden! Verwende Deinen Source aus dem ersten Posting, verweise "OnPrivateMessage" auf eine "thread interne" Methode. Dort verarbeite die "Message" nach belieben, soll allerdings Interaktion mit der GUI stattfinden(z.B. Anzeige der Nachricht im Memo) muss das ganze über Thread.Syncronize gemacht werden. Zu Deiner Frage bezüglich des OnExecute: Die Procedure die Du definiert hast für OnPrivateMessage wird automatisch aufgerufen, darum "kümmert" sich IdIrc. Deshalb musst Du, soweit ich das im Moment beurteilen kann, im Onexecute einfach eine Schleife laufen lassen, solange die IRC Verbindung steht den hread einfach schlafen legen(z.b. Sleep(25)). Gibt noch andere Möglichkeiten, aber zum Testen sollte das reichen. Greetz Data |
AW: [Indy 10] IRC-Client in eigenem thread auslagern
Danke erstmal für die Tipps und die Info, gebracht hats aber scheinbar nicht viel, ich habe zudem mal probeweise die proceduren "onraw" und "onstatus" hinzugefügt, diese Funktionieren auch (man sollte zudem bemerken, wenn ich über IRC.Raw eine Naricht schicke wird diese gesendet (, kommt auch brav beim Server an) und wird bei "OnRaw" angezeigt, empfangen kann ich immernoch keine Narichten (Status, ping-pong,ect. geht, nur eben das wichtigste der chat selber eben nicht).
Momentane Source (ich war zu faul Form66 wieder in Form1 umzubenennen :D):
Delphi-Quellcode:
So sieht die Memo aus, nach einem Connect und nachdem ich was gesendet und empfangen habe(n sollte):
unit Unit66;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, IDIRC, IDContext, StdCtrls, IdBaseComponent, IdComponent; type TForm66 = class(TForm) Memo1: TMemo; Button1: TButton; Button2: TButton; Edit1: TEdit; Button3: TButton; procedure FormDestroy(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button3Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; type TIRC = class(TThread) private IRC : TIDIRC; FConnected : Boolean; FMessage : String; procedure OnPrivateMessage(ASender: TIdContext; const ANicknameFrom, AHost, ANicknameTo, AMessage: String); procedure OnStatus(ASender: TObject; const AStatus: TIdStatus;const AStatusText: string); procedure OnRaw(ASender: TIdContext; AIn: Boolean; const AMessage: String); procedure WriteMessageInMemo; public Host, Channel, Name : AnsiString; Port : Word; constructor Create(CreateSuspended:Boolean); procedure StartIRC; procedure SendText(Content : AnsiString); procedure Execute; override; destructor Free; end; var Form66: TForm66; AIRC : TIRC; implementation {$R *.dfm} constructor TIRC.Create(CreateSuspended: Boolean); begin inherited Create(CreateSuspended); IRC := TIDIRC.Create(nil); IRC.OnPrivateMessage := OnPrivateMessage; IRC.OnStatus := OnStatus; IRC.OnRaw := OnRaw; end; procedure TIRC.StartIRC; begin IRC.Host := Host; IRC.Port := Port; IRC.Username := Name; IRC.Realname := Name; IRC.Nickname := Name; IRC.Connect; IRC.Join(Channel); FConnected := True; end; procedure TIRC.Execute; var ASender : TIDContext; ANick,AHost,ANickTo,AMessage : String; begin while (not Self.Terminated) do begin // if (FConnected) and (IRC.Connected) then Sleep(25); end; IRC.Disconnect('Ich hau ab!'); end; destructor TIRC.Free; begin try IRC.Free; except end; inherited Destroy; end; procedure TForm66.Button1Click(Sender: TObject); begin Button1.Enabled := False; Button2.Enabled := True; AIRC := TIRC.Create(False); with AIRC do begin Host := '*****.ath.cx'; Port := 6667; Channel := 'Testchannel'; Name := 'Testuser'; StartIRC; end; end; procedure TForm66.Button2Click(Sender: TObject); begin Button2.Enabled := False; Button1.Enabled := True; AIRC.Terminate; end; procedure TForm66.Button3Click(Sender: TObject); begin if Edit1.Text <> '' then begin AIRC.SendText(Edit1.Text); Edit1.Text := ''; end; end; procedure TForm66.FormDestroy(Sender: TObject); begin if not AIRC.Terminated then AIRC.Terminate; end; procedure TIRC.SendText(Content: AnsiString); begin IRC.Raw('PRIVMSG '+'#'+Channel+' :'+Content); end; procedure TIRC.OnStatus(ASender: TObject; const AStatus: TIdStatus;const AStatusText: string); begin FMessage := AStatusText; Synchronize(WriteMessageInMemo); end; procedure TIRC.OnPrivateMessage(ASender: TIdContext; const ANicknameFrom: string; const AHost: string; const ANicknameTo: string; const AMessage: string); begin FMessage := ANicknameFrom +': '+ AMessage; Synchronize(WriteMessageInMemo); end; procedure TIRC.OnRaw(ASender: TIdContext; AIn: Boolean; const AMessage: String); begin FMessage := AMessage; Synchronize(WriteMessageInMemo); end; procedure TIRC.WriteMessageInMemo; begin if FMessage <> '' then begin Form66.Memo1.Lines.Add(FMessage); FMessage := ''; end; end; end. Zitat:
Vielen Dank schonmal |
AW: [Indy 10] IRC-Client in eigenem thread auslagern
Hi,
der Source sieht soweit eigentlich schon ganz gut aus, wie gesagt ich kenne die Kompo "TIdIRC" noch nicht aus persönlicher Erfahrung, deshalb kann ich keine fehlerhafte Implementierung der Indys ausschliessen, das würde mich aber sehr wundern. Welche Version der Indys verwendest Du ? denn aktuellen Branch aus dem SVN oder die mit Delphi ausgelieferte Version ? Bekommst Du den das Event OnPrivateMessage, wenn Du die Komponente ohne Thread verwendest ? Für Deinen Source habe ich eigentlich nur Änderungsvorschlag :
Delphi-Quellcode:
procedure TIRC.Execute;
var ASender : TIDContext; ANick,AHost,ANickTo,AMessage : String; begin // ich würde den Thread suspended erzeugen, komplett connecten und erst danach den Thread starten/resumen // dann kann hier auch auf connected geprüft werden while (not Self.Terminated) and (IRC.Connected) do begin // if (FConnected) and (IRC.Connected) then Sleep(25); end; IRC.Disconnect('Ich hau ab!'); end; |
AW: [Indy 10] IRC-Client in eigenem thread auslagern
Hey,
wie von mir erwarted hat das suspended erzeugen und das aufrufen von Connect im Execute nichts gebracht... Ich verwende die bei Delphi 2009 mitgelieferte Version (Datum:29.08.2008), die Komponente (und OnPricateMessage) funktioniert, wenn ich sie ohne Thread direkt zur laufzeit erzeuge... Grüßle (ich schau mal nach der aktuellsten Indy Verison und melde mich dann wieder) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:01 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