IRC Klasse einbinden
-
Hi @all,
ich bin gerade dabei eine IRC-Klasse einzubinden. Die Klasse hab ich von
http://codeguru.earthweb.com/network/irc.html
Also mein Programm ist Dialogfeldbasierend. Ich lese die Serverdaten ein und übergebe sie an IrcSession.Connect() in der Hoffnung, das anschließend bei Start die Verbindung hergestellt wird.CIrcIdentServer m_identServer; CIrcSession m_IrcSession; // Datenübergabe an irc m_IrcInfo.sServer = m_strServer; m_IrcInfo.iPort = m_iPort; m_IrcInfo.sNick = m_strNick; m_IrcInfo.sPassword = m_strPass; m_IrcSession.Connect(m_IrcInfo); m_identServer.Start(m_IrcInfo.sUserID.c_str());Ich kann das aber leider nicht überprüfen, weil ich nicht weiß, wo ich den String der Serverantwort herbekomme. Es muß doch eine Funktion dafür geben.
Ich dachte eigentlich an Listen() oder so.
Aber in der Socket.cpp sieht das so aus.bool Socket::Listen() { return listen(m_sock, 5) != SOCKET_ERROR; }Ihr würdet mir sehr helfen, wenn mir einer sagen kann:
1. Setze ich die Verbindung korrekt. Wenn nein, wie mach ich es richtig?
2. In welcher Funktion/Klasse bekomme ich die Serverantwort?
3. An welcher Funktion/Klasse muß ich die Strings für die Messages übergeben?Vielen Dank an jedem, der sich die Mühe macht dieses Posting zu lesen.

-
**** mach aktuell ****
-
Hi !
Ok..es ist viel Quellcode, also, mal sehen ob ich Dir helfen kann, etwas Licht da rein zu
bekommen.Erstmal muss man ja mit nem Server connecten. Das passiert über Sockets. Das eigentliche Senden
und Empfangen der Daten läuft auch über Sockets.Der Wesentliche Verbindungsablauf ist, Socket erstellen:
if( !m_socket.Create() ) throw "Failed to create socket!"; Wenns nicht geklappt hat,
Excetpion-Throw.
Wenns geklappt hat, Socket mit dem IRC-Server verbinden:
if( !m_socket.Connect(addr) ) ;throw "Failed to connect to host!";
Wenn keine Verbindung zu Stande kommt, ebenfalls Exception-Throw.Wenn bis hier alles glatt läuft, ist die Verbindung zum Server geglückt, jetzt wird
der zweite Thread gestartet, mit:
m_hThread = CreateThread(NULL, 0, ThreadProc, this, 0, NULL)
In diesem Threat empfängt das soeben erstellte und verbundene Socket die Nachrichten vom Irc-
Server und den Usern.
pThis->DoReceive(); Das Socket geht quasi in eine Art Thread-Empfangsscheife.Jetzt werden Nick, Username, eventuell Passwort, der Computername, eventuell Ne Identd an
den Irc-Server mit dem Send-Befehl über das Socket geschickt:
m_socket.Send("PASS %s\r\n", info.sPassword.c_str());
m_socket.Send("NICK %s\r\n", info.sNick.c_str());
m_socket.Send("USER %s %s %s :%s\r\n",Mehr oder weniger gleichzeitig wird ein zweites Socket, welches den Identd-Server darstellt,
ins Leben gerufen: if( !m_socket.Create() ) return false;
Das ist jetzt neu:if( !m_socket.Bind(InetAddr(uiPort)) )
{
m_socket.Close();
return false;
}
Das Socket wird an einen Port "gebunden", den die Funktion InetAddr liefert. An diesem Port
lauscht der Indend-Server auf eingehende Ident-Anfragen und beantwortet diese.
Meistens der AUTH Port, nr 113.Das versetzt den Identd Server in den "Lauschmodus", um auf Identd Anfragen zu antworen
bool Socket::Listen()
{
return listen(m_sock, 5) != SOCKET_ERROR;
}Das eigentliche Empfangen der Daten, läuft in der Funktion void CIrcSession::DoReceive() ab.
Achja, hätte ich fast vergessen...wenn ein Socket bereit ist Daten zu empfangen, wird die
Funktion Accept ausgelöst.
Naja, den Client-Server-Ablauf muss man mal selbst programmiert haben, um da richtig
hinterzusteigen. Ist mit den MFC Klassen zum Beispiel gar nicht so schwer.
Ich lasse das jetzt mal mit den Sockets...verweise an weiterführende Literatur, *g*,
und "sage" mal noch ein paar Takte zu dem "Rest" des Quellcodes.Ok, also die Verbindung steht....
....wenn im Fenster zum Nachricht Senden die Return taste gedrückt wird,
dann wird die Funktion OnIrcMessageEdited(WPARAM, LPARAM) der Klasse CTryIRC2View aufgerufen.
In dieser tritt die Funktion GetWindowText(s) in Aktion, welche den vom User
eingegebenen Text in der Variable s speichert.Bevor dieser Text an das Anischt-Chatfenster und an den IRC-Server weiter-
gegeben werden kann, muss dieser vorher noch geparst werden. (RFC 1459 -gerecht, möglichst)Diese Aufgabe des Parsens übernimmt die Klasse CIrcMessage. An diese Klasse wird der eingegebene
String weitergegeben. Die Memberfunktion ParseIrcCommand(const char* lpszCmdLine) erledigt das.(Da darf ich gar nicht so genau hinsehen *schluck* ich hatte doch tatsächlich vor, so einen
Parser selbst zu schreiben....naja...vielleicht wenn ich mal irdendann gaaaanz
besoders viel Zeit haben sollte )...jo...zurück zum Thema...ääääääh..achja...nun ist der vom User eingegebene String also
geparst. Die Funktion gehrt nun zurück zu OnIrcMessageEdited(WPARAM, LPaRAM).Der geparste Text wird jetzt per Stream-Input in das Objekt g_ircSession der Klasse
CIrcSession geleitet.
Das sagt diese Zeile aus: g_ircSession << irc::CIrcMessage(s);
SetWindowText(_T("")) löscht den eingegebenen Text in der Eingabezeile.Die Klasse CIrcSession arbeitet in einem zweiten Thread und ist für die Verteilung der
Nachtichten an die jeweiligen Ansichts-Chatfenster zuständig.Für die Ansichts-Chatfenster sind wiederum die Klassen CIrcDefaultMonitor und CIrcMonitor zuständig.
Das eigentliche Daten Senden und empfangen passiert in der Klasse Socket.
Dorthin werden die Nachrichten geschleust und von dort auch geholt.Boah ey ich fasse es nicht, habe ich mich jetzt "festgelabert" und dabei fast das Wesentliche
aus den Augen verloren, Deine Fragen....also....vom IRC kommende Nachrichten sind die Identd-Anfragen ( braucht man bei den meisten IRC
Servern nicht unbedingt) und natürlich das Wichtigste, die Nachrichten von dem Irc-Server und
den Usern.void CIrcSession::DoReceive() empfängt diese.
Kannst Du z.B. mit nem AfxMessageBox(cbInBuf) abfangen und anzeigen lassen.
void CIrcSession::DoReceive() empfängt diese.
.....
chBuf[cbInBuf] = '\0';
AfxMessageBox(chBuf); <------- eingefügt
char* pStart = chBuf;
.....
So und die ausgehenden Nachrichten kannst Du hier abfangen:
LRESULT CTryIRC2View::OnIrcMessageEdited(WPARAM, LPARAM)
.....
CString s;AfxMessageBox(s); <---- ne Möglichkeit, abfangen und Anzeigen lassen
m_wndUserText.GetWindowText(s);
if( s.GetLength() == 0 )
return 0;....
Soo...alle Klarheiten beseitig?? *g* Mit den Sockets hab ich mich etwas verhaspelt, aber vielleicht hilft es ja trotzdem ein bisschen weiter.
Tschüs, Joe
-
Hi Joe,
das ist erstmal allerhand.
Vielen Dank das Du dir die Mühe machst, es so genau zu erklären.
Ich hab jetzt erstmal ne Menge durchzuarbeiten.
Bis dahin
-
Hi Joe,
ein paar Probleme hab ich noch.
1. Ich wollte, wie Du beschrieben hast bei DoReceive() die Msg abfangen.
MitAfxMessageBox(chBuf);funktioniert das auch. Jetzt wollte ich die allerdings in meinem Editfeld anzeigen lassen.
CIrcClientDlg::m_cMsg.AddString(chBuf); UpdateData(FALSE);Der erkennt allerdings CIrcClientDlg nicht. Wenn ich die Header-Datei IrcClientDlg.h in die irc.h aufnehme gibt es 33 Fehler.

Was mach ich falsch?
2. Ich habe CIrcSessinoInfo um sJoin erweitert um einen Chatraum zu eröffnen/beizutreten. Die übergebe ich mit
CString temp = "/JOIN "; temp = temp + m_IrcInfo.sJoin.c_str(); CIrcMessage::CIrcMessage(temp); // ist das Parsen so richtig??? m_MySocket.Send(temp,sizeof(temp)); temp = temp.Mid(1); m_cMsg.AddString(temp); // Dient der eigenen Anzeige UpdateData(TRUE);ich bekomme aber keine Rückmeldung über DoReceive().
3. Wenn ich das Programm verlassen will schließe ich das über meine Logout-Tastem_IrcSession.Disconnect();Dann beibt das Programm hängen. Wenn ich die Verbindung aufgebaut habe und über OnClose() das Programm beende, kommt ne Fehlermeldung, die zeigt das Disconnect noch aufgerufen wird.
4. Warum antwortet das Progamm nicht auf nen ping, bzw wo baut man sowas ein?
Ich denke, wenn ich Antworten auf die vier Fragen bekomme, sollte das Programm laufen. Drum bitte sagt mir was ich falsch mache.
-
Letztes posting stark überarbeitet.
-
Hallo !
Na, Du hast ja ne Menge vor, wie mir scheint !
Nimm mir bitte folgende Aussage nicht übel, aber:
Hast Du Dir da nicht ein bisschen zuviel vorgenommen, wenn es schon beim
Einbinden einer Headerdatei hapert ?Die Klassen von Adi Degani beinhalten recht komplexe Programmiertechniken, wie z.B. das starten eines Threads, usw...
Wie stehtst Du zu dem Vorschlag, das Du erstmal selbst z.B. ein
Dialogbasiertes, kleines Programm schreibst, das sich mit nem IRC-Server
verbindet.
Dann kannst Du sehr gut sehen, wie das mit den Sockets und der Verbindungs-Reihenfolge mit einem IRC-Server funktioniert (connect, accept, receive, usw.)Die MFC-CAsyncSocket-Klasse bietet hierfür recht Komfortabel Funktionen an.
Diesbezüglich helfe ich Dir gern weiter, aber mich weiterhin duch den Code-Dschungel von Adi Degani durchzuwurschteln, dazu fehlt mir jegliche Motivation.Gruß, Joe
-
Und Sockets werden im Buch VC++ 6 in 21 Tagen sehr gut erklärt. Such mal in der FAQ. Da gibt es den Link zum Online lésen.
-
Hi Joe,
ich wollte nicht dass der Eindruck erweckt wird, dass Du qasi das Programm für mich schreiben sollst. Ist ja auch gar nicht nötig, hat ja Adi Degani schon getan.
Die Sock - Klasse aus VC++ 6 in 21 Tagen habe ich auch schon programmiert und kann das jetzt auch schon besser nachvollziehen.
Wo mir wirklich was fehlt, ist das Verständnis wie ich externe Klassen einbinde und wie ich erkenne, wo ich diese Ansprechen muß.
z.B. das Headerproblem. Mir ist total unverständlich warum ich meine IrcClientDlg.h nicht in die irc.h einbinden kann. Oder warum ich hin und wieder mit using namesspace irc arbeiten muß.
Ein gutes Tutorial hierüber wäre nicht schlecht.
Ich danke dir aber trotzdem.
-
Trikor schrieb:
Mir ist total unverständlich warum ich meine IrcClientDlg.h nicht in die irc.h einbinden kann.
Kannst du doch. Ich versuchs mal zu erklären.
Also. Wenn du eine neue Klasse in deinem Projekt verwenden willst, musst du natürlich ersteinmal die Klassendefinitionsdatei (cpp-Datei) deinem Projekt hinzufügen (Projekt->Dem Projekt hinzufügen->Dateien) hinzufügen. Ist ja klar, dein Programm muss ja den Code der Klassen wissen.
Die Headerdatei deiner Klasse musst du nicht hinzufügen (da du das ja immer im Code mit #include machst), wenn du sie aber hinzufügst, hat dies den Vorteil, dass deine Klasse in der Klassenliste erscheint und die Automatische Verfollständigung /bzw. Elemente Auflistung während dem Programmieren funktioniert.
Die Klassenheaderdateien sind (normalerweise) mit einem Schutzmechanismus versehen, dass man sie nicht doppelt includieren kann:#ifndef EINDEUTIGE_KONSTANTE // wenn das Symbol EINDEUTIGE_KONSTANTE noch nicht definiert ist, führe folgenden Code aus #define EINDEUTIGE_KONSTANTE // definiere EINDEUTIGE_KONSTANTE /* Die Deklaration der Klasse */ #endif // Code bis hier ausführen (falls EINDEUTIGE_KONSTANTE nicht definiert war)Wenn du dein Projekt kompilierst, fügt der Compiler alle Dateien nacheinander (angefangen bei deiner "Hauptdatei") zusammen.
Da ja jede Headerdatei (durch den Schutzmechanismus) nur einmal eingebunden wird (sonst gäbs ein Compilerfehler), ist es egal, in welchen Dateien du die Klassenheader mit #include einbindest.
Dh. du kannst auch 40 mal #include schreiben
Hoffe ich konnte dir helfen.
Grüße Rapha
-
Hi Rapha,
ich glaub, ich hab das noch nicht ganz verstanden.
Ich habe die Headerdateien (irc.h socket.h CrossThreadsMessagingDevice.h) über Project / Dateien hinzugefügt.
In meiner Hauptdlg habe ich jetzt#ifndef _IRCCLIENTDLG_H #define _IRCCLIENTDLG_H #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 using namespace irc;Aber jetzt erkennt die Klasse das using namespace irc nicht mehr.
Und aus der irc.cpp kann ich immer noch nicht auf ircClientDlg zugreifen.
-
Huhu "!!!"
Schade, wollte grade Quellcode zusammenstellen, wie man nen IRC Server connecten kann....naja..egaaal.
Ok, Thema #include und namespace:
Dein #include Problem könnte dieses sein:
Du hast zwei Klassen, Klasse A und Klasse B.
Jetzt brauchst du in Klasse A das Objekt B und umgekehrt.Da jetzt A von B abhängt und umgekehrt, kannst Du
die benötigten Objekte als Zeiger deklarieren und
fürs jeweils benötigte Objekt die Vorwärtsdeklaration benutzen.
Ich schreibe mal ein Beispiel:#include "A.h"
class B; //<---- Vorwärtsdeklaration
class A
{
public:private:
B* m_b;
};#include "B.h"
class A; //<---------- Vorwärtsdeklaration
class B
{public:
private:
A* m_a;
};Also, mit Zeigern und den Vorwärtsdeklarationen funzt das

Ok, jetzt zu der Namespace-Geschichte;
Namespace, ein Namensraum, wird benutzt, um Namenskonflikte zu
vermeiden.
Der arme Compiler weiss sonst gar nicht was er machen soll. *g*// A.h
.....
void Bescheid()
{
AfxMesageBox("Ich bin in A.h deklariert");
} .....// B.h
....
void Bescheid()
{
AfxMesageBox("Ich bin in B.h deklariert");
}
.....// Hauptprogramm
#include "A.h"
#include "B.h"Bescheid() // welches Bescheid ??
// Ende Hauptprogramm
Um Namenskonflikte zu vermeiden, kann man diese Namespace-Geschichte
Benutzen.// A.h
namespace A
{
void Bescheid
{
AfxMesageBox("Ich bin in A.h deklariert");
}
} // ende namespace// B.h
namespace B
{
void Bescheid()
{
AfxMesageBox("Ich bin in B.h deklariert");
}
}; // ende namespace// Hauptprogramm
#include "A.h"
#include "B.h"...
using namespace A;
Bescheid(); // Message-Box aus A.h wird aufgerufen
...
// Ende HauptprogrammGruß, Joe
-
Hi Joe,
das hast Du wirklich klasse erklärt. Danke

Wenn nicht schon 10 postings vorher wären, würd ich das für die FAQ´s empfehlen.
Leider muß ich feststellen, das immer wenn ich ein Problem (beim Einbinden der
Klassen von Adi Degani) gelöst habe, kommen zwei neue hinzu.
Deshalb versuche ich jetzt, wie Du sagtest mal nen IRC-Client selber zu programmieren. Hab ja schon einiges gelehrnt.
Ich werd auf jeden Fall wissen lassen, wie es ausgeht.
Wer weiß, vieleicht schreibe ich auch mal ein kleines Tutorial, wie man IRC in eine dialogbasierende Anwendung einbindet. Vorausgesetzt ich schaffe es.
Aber es gibt definitiv zu wenig Lektüre darüber.
-
Super, das ist der richtige Weg und die richtige Einstellung
