Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   [Python] Nachricht an IRC-Channel senden/empfangen (https://www.delphipraxis.net/116109-%5Bpython%5D-nachricht-irc-channel-senden-empfangen.html)

cruso 23. Jun 2008 17:48


[Python] Nachricht an IRC-Channel senden/empfangen
 
Hi!

Ich möchte einen kleinen IRC-Bot in Python schreiben. Nur leider findet man keine gescheiten Informationen dazu, den die Codeschnipsel sind entweder falsch oder einfach viel zu überladen. Habt Ihr eine Idee, wie das gehen könnte? Also wie man sich zum richtigen Server und dann zum richtigen Channel verbindet und wie man dort dann Nachrichten sendet und die Eingegebenen empfängt?

Das dürften eigentlich nicht viel mehr als 12-15 Zeilen Code sein...


Ich danke Euch schon jetzt für Eure Antworten!




MfG
Cruso

Valle 23. Jun 2008 17:49

Re: [Python] Nachricht an IRC-Channel senden/empfangen
 
Benutzt du ein IRC-Modul oder implementierst du das Protokoll mit einem Socket selbst?

Mit freundlichen Grüßen,

Valle

cruso 23. Jun 2008 17:49

Re: [Python] Nachricht an IRC-Channel senden/empfangen
 
Zitat:

Zitat von Valle
Benutzt du ein IRC-Modul oder implementierst du das Protokoll mit einem Socket selbst?

Mit freundlichen Grüßen,

Valle

Ich benutze eigentlich kein Modul...

Valle 23. Jun 2008 17:51

Re: [Python] Nachricht an IRC-Channel senden/empfangen
 
Zitat:

Zitat von cruso
Zitat:

Zitat von Valle
Benutzt du ein IRC-Modul oder implementierst du das Protokoll mit einem Socket selbst?

Mit freundlichen Grüßen,

Valle

Ich benutze eigentlich kein Modul...

Dann musst du das Protokoll selbst implementieren. Das sind dann doch wohl etwas mehr als so 15 Zeilen. Schließlich musst du mit dem Socket arbeiten, die Messages parsen usw usf. Hast du schon irgendeinen Ansatz? Schon was angefangen?

Mit freundlichen Grüßen,

Valle

cruso 23. Jun 2008 17:55

Re: [Python] Nachricht an IRC-Channel senden/empfangen
 
Naja soviel ich weiß, müsste ich nur Nachrichten zum Server schicken, die halt entsprechend dem IRC-Protokoll sind...

Valle 23. Jun 2008 18:10

Re: [Python] Nachricht an IRC-Channel senden/empfangen
 
Zitat:

Zitat von cruso
Naja soviel ich weiß, müsste ich nur Nachrichten zum Server schicken, die halt entsprechend dem IRC-Protokoll sind...

So einfach ist es nicht. Natürlich musst du dem Server einige Nachrichten schicken, aber das ganze ist mit einer gewissen Interaktion verbunden. Einfach verbinden, senden und wieder raus geht nicht. Schon alleine aus dem Grund, dass der Server dich nach dem Prinzip nach einigen Versuchen sperren wird. *g* (d.h. wenn überhaupt, dann muss der Bot durchlaufen)

Ok, mal zur Praxis zurück. Als ich eben schrieb "So einfach ist es nicht" wollte ich eigentlich nur sagen, dass es wahrscheinlich mehr als 15 Zeilen. Die Umsetzung selbst dürfte nicht das Problem sein. Ich schreibe mal ein paar Zeilen aus meinem Bot. (Der mittlerweile ca. 750 Zeilen hat und noch längst nicht fertig ist.)

Am sinnvollsten ist es, das ganze in eine Klasse zu packen. So zum Beispiel:

Code:
import socket

class irc:

    _socket = None
Dann noch eine connect-Methode reinmachen. (Ich übernehme einfach mal aus meinem Bot. Kannst ihn dann halt nicht 1:1 übernehmen, aber das machst du ja auch so nicht. ;-) )

Code:
    def connect(self, hostname, port):
        if self._socket == None:
            self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            try:
                self._socket.connect((str(hostname), int(port)))
            except:
                self.log("Connection to "+str(hostname)+":"+str(port)+" failed.")
                self._socket = None
                return False
            self._hostname = str(hostname)
            self._host = int(port)
            self.log("Connection established to "+str(hostname)+":"+str(port)+".")
            return True
        else:
            self.log("Socket already connected to: "+str(self._hostname)+":"+str(self._port)+"!")
            return False
Und dann einen Main-Loop. Der Main-Loop ist (wie der Name auch schon sagt) eine Schleife, die immer und immer wieder durchläuft. In ihr wird überprüft ob ein neuer Befehl von Server eingetroffen ist und ggf. wird ein Befehl zurückgesendet. Wenn man diese Methode einmal aufruft wird der Code danach erstmal nicht ausgeführt. Das erwähne ich hier, weil es schonmal ziemlich verwirren kann, wenn man den Main-Loop startet und in der nächsten Zeile in einen Channel reinwill. *g*

Code:
    def main_loop(self):
        if self._socket == None:
            self.log("Socket is not connected to an IRC-Server!")
            return False
        else:
            // Dieser Code muss nur EINMAL beim Verbinden gesendet werden.
            // Eigentlich ist dies garnicht der richtige Ort fuer den Code,
            // denn er gehoert eigentlich zum connect. Dennoch ist er hier nicht
            // ganz falsch. Wichtig ist, dass man nach dem Connect gleich den
            // Main-Loop aufruft, sonst kann es sein dass der Server dich
            // wegen einem Timeout rausschmeisst.
            if not self.send("NICK :"+self._nickname):
                self.log("Couldn't send NICK-message!")
                self.disconnect()
            else:
                if not self.send("USER "+self._nickname+" _ _ :"+self._realname):
                    self.log("Couldn't send USER-message!")
                    self.disconnect()
            recv = ""
            while self._socket != None:
                buffer = self._socket.recv(1)
                if buffer == "\n" or buffer == "\r":
                    if recv.strip("\n\r ") != "":
                        // Die parse-Methode parst die Nachricht und bringt sie in ein
                        // benutzbares Format. In meinem Fall ein indiziertes Array,
                        // bzw unter Python "dict".
                        message = self.parse(recv)
                        // message_dispatch reagiert auf die jeweiligen Nachrichten
                        // vom Server. Gibt bei einer Nachricht eines Users zum Beispiel
                        // die Nachricht aus oder antwortet auf einen Ping.
                        self.message_dispatch(message)
                        recv = ""
                else:
                    recv += buffer
            self.log("Main-loop finished. ")
Was noch wichtig zu erwähnen ist: Der Server sendet in regelmäßigen Abständen einen Befehl namens "Ping" zu dir. Du musst auf diesen Befehl mit einem "Pong" antworten, sonst fliegt dein Bot aus dem IRC. (Das nennt man dann Ping-Timeout)

Also jetzt viel Spaß beim implementieren des IRC-Protokolls. Es werden mehr als 15 Zeilen. :-P Eines möchte ich dir noch mitgeben. Das wird in den nächsten Stunden dein Freund sein. Hier die IRC-Spezifikation. Halte dich an die und du schaffst das. ;-)

RFC 1459

Mit freundlichen Grüßen,

Valle

cruso 23. Jun 2008 18:14

Re: [Python] Nachricht an IRC-Channel senden/empfangen
 
Naja 750 Zeilen sind imho erstmal übertrieben (zumindest für meine Zwecke). Aktuell möchte ich eigentlich nur Nachrichten schicken (z.B. Eine)...

Valle 23. Jun 2008 18:21

Re: [Python] Nachricht an IRC-Channel senden/empfangen
 
Zitat:

Zitat von cruso
Naja 750 Zeilen sind imho erstmal übertrieben (zumindest für meine Zwecke). Aktuell möchte ich eigentlich nur Nachrichten schicken (z.B. Eine)...

Naja, mein Bot kann ja auch ein wenig mehr.
Aber alleine die Zeilen da oben kommen ja schon auf 50...

Mit freundlichen Grüßen,

Valle

cruso 23. Jun 2008 23:27

Re: [Python] Nachricht an IRC-Channel senden/empfangen
 
Also wenn man nur eine Zeile senden will, dann sind das nur 10 Codezeilen. Habe es jetzt herausgefunden. Ist ganz einfach. Morgen Poste ich mal den Code...

Btw: Weiß jemand wie man mit nem Bot bei irc.quakenet.org reinkommt? Bei Freenode gehts, doch bei Quakenet nicht. Habt ihr eine Idee?


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:18 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz