AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi [Indy 10] IRC-Client in eigenem thread auslagern

[Indy 10] IRC-Client in eigenem thread auslagern

Ein Thema von Sfaizst · begonnen am 10. Dez 2010 · letzter Beitrag vom 22. Dez 2010
Antwort Antwort
Seite 1 von 2  1 2   
Sfaizst

Registriert seit: 16. Jun 2008
33 Beiträge
 
#1

[Indy 10] IRC-Client in eigenem thread auslagern

  Alt 10. Dez 2010, 03:43
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:
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;
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...

Viele Grüße

Sfaizst

Geändert von Sfaizst (10. Dez 2010 um 04:13 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von s.h.a.r.k
s.h.a.r.k

Registriert seit: 26. Mai 2004
Ort: Offingen
3.159 Beiträge
 
Delphi XE Professional
 
#2

AW: [Indy 10] IRC-Client in eigenem thread auslagern

  Alt 10. Dez 2010, 03:53
Laufen die Indys nicht schon von Haus aus in einem Thread? D.h. darum müsstest du dich gar nicht kümmern.
Armin
»Remember, the future maintainer is the person you should be writing code for, not the compiler.« (Nick Hodges)
  Mit Zitat antworten Zitat
Sfaizst

Registriert seit: 16. Jun 2008
33 Beiträge
 
#3

AW: [Indy 10] IRC-Client in eigenem thread auslagern

  Alt 10. Dez 2010, 04:12
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.
  Mit Zitat antworten Zitat
Benutzerbild von DataCool
DataCool

Registriert seit: 10. Feb 2003
Ort: Lingen
884 Beiträge
 
Delphi XE3 Enterprise
 
#4

AW: [Indy 10] IRC-Client in eigenem thread auslagern

  Alt 10. Dez 2010, 09:15
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.
Der Horizont vieler Menschen ist ein Kreis mit Radius Null, und das nennen sie ihren Standpunkt.
  Mit Zitat antworten Zitat
Sfaizst

Registriert seit: 16. Jun 2008
33 Beiträge
 
#5

AW: [Indy 10] IRC-Client in eigenem thread auslagern

  Alt 11. Dez 2010, 11:52
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:
P.S.: Ohnen Thread sollte man die TIdAntiFreeze Komponente auf die Form ziehen.
Funktioniert dies nur bei Komponenten die zur Designtime erstellt wurden oder auch bei denen, die zur Laufzeit erstellt werden? (hatte zudem nie besonders viel Freude mit TIdAntifreeze als ich mit TIDHttp rumgespielt hatte und damit einen Download realisiert hatte, da war das auslagern im eigenem Thread wesentlich besser)

Sfaizst

Geändert von Sfaizst (12. Dez 2010 um 03:40 Uhr) Grund: undeutlich formuliert :D
  Mit Zitat antworten Zitat
Sfaizst

Registriert seit: 16. Jun 2008
33 Beiträge
 
#6

AW: [Indy 10] IRC-Client in eigenem thread auslagern

  Alt 21. Dez 2010, 22:29
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
  Mit Zitat antworten Zitat
Benutzerbild von DataCool
DataCool

Registriert seit: 10. Feb 2003
Ort: Lingen
884 Beiträge
 
Delphi XE3 Enterprise
 
#7

AW: [Indy 10] IRC-Client in eigenem thread auslagern

  Alt 22. Dez 2010, 00:28
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
Der Horizont vieler Menschen ist ein Kreis mit Radius Null, und das nennen sie ihren Standpunkt.
  Mit Zitat antworten Zitat
Sfaizst

Registriert seit: 16. Jun 2008
33 Beiträge
 
#8

AW: [Indy 10] IRC-Client in eigenem thread auslagern

  Alt 22. Dez 2010, 05:23
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 ):

Delphi-Quellcode:
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.
So sieht die Memo aus, nach einem Connect und nachdem ich was gesendet und empfangen habe(n sollte):
Zitat:
Resolving hostname *****.ath.cx.
Connecting to **.**.***.**.
Connected.
NICK Testuser
USER Testuser 0 * :Testuser
NICK :Testuser
001 Testuser :Welcome to the My IRC Network Testuser!Testuser@........de
002 Testuser :Your host is ......, running aIRCServer
003 Testuser :This server was created Thu Jun 14 at 2001
004 Testuser ...... aIRCServer iswo opsitnmlbvk
005 Testuser ...:are available on this server
251 Testuser :There are 4 users and 1 services on 1 servers
252 Testuser 0 perator(s) online
253 Testuser 3 :unknown connection(s)
254 Testuser 3 :channels formed
255 Testuser :I have 4 clients, 1 services and 1 servers
422 Testuser :MOTD File is missing
PRIVMSG #62.141.39.44-10052 :Hallo //Habe ich gesendet!
//HIER FEHLT DIE NARICHT DIE EMPFANGEN WERDEN SOLLTE....
QUIT :Ich hau ab! //Disconnect Button
Disconnecting.
Disconnected.
Ich hoffe du kannst mir weiterhelfen, ich kenns hald von den guten alten Sockets, dass ich die im Execute von Windows "abholen" musste.. deswegen bin ich auch beim IRC davon ausgegeangen, wenn ich jedoch seh, dass eigentlich alles geht kanns das ja auch nicht sein (wie du sagtest, da kümmert sich irc selber drum...)

Vielen Dank schonmal

Geändert von Sfaizst (22. Dez 2010 um 05:29 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von DataCool
DataCool

Registriert seit: 10. Feb 2003
Ort: Lingen
884 Beiträge
 
Delphi XE3 Enterprise
 
#9

AW: [Indy 10] IRC-Client in eigenem thread auslagern

  Alt 22. Dez 2010, 09:47
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;
Der Horizont vieler Menschen ist ein Kreis mit Radius Null, und das nennen sie ihren Standpunkt.

Geändert von DataCool (22. Dez 2010 um 09:49 Uhr) Grund: Was vergessen
  Mit Zitat antworten Zitat
Sfaizst

Registriert seit: 16. Jun 2008
33 Beiträge
 
#10

AW: [Indy 10] IRC-Client in eigenem thread auslagern

  Alt 22. Dez 2010, 12:44
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)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:06 Uhr.
Powered by vBulletin® Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2019 by Daniel R. Wolf