Kirjoittelen Pythonilla erään aikaisemman keskustelun innoittamana pientä IRC-bottia lähinnä tutkiakseni, miten irkki käyttäytyy ohjelmoijan käsittelyssä. Loistavan alun ja RFC:n lukemisen jälkeen en kuitenkaan saa bottiani pysymään irkissä kovin kauaa. Connectaaminen onnistuu aivan normaalisti, vaikka serveriltä tuleekin pari "register first"-viestiä, mutta muutaman minuutin kuluttua kanavalle joinimisesta botti putoaa Ping timeout -viestin saattelemana.
Päättelin viestistä, että ongelma on PING-pyyntöön vastaamisessa. Mutta mielestäni olen hoitanut asian aivan oikein, sillä palvelimelle yhdistäessä botti vastaa aivan oikein PING :numerosarja -viestiin (PONG :numerosarja). Botti ei edes tulosta viestiä uudesta PING-pyynnöstä kanavalle liittymisen jälkeen.
Ohjelma pyörii yhdistämisen jälkeen ikuisessa silmukassa vastaanottaen viestejä palvelimelta muodossa viesti = str(irc.recv(4096))
, minkä jälkeen viesti-muuttuja tulostetaan. Kun botti on pudonnut, ohjelma pyörii silmukassa ilman mitään viestiä tai reaktiota yhteyttä koskien.
Mikä voisi olla vikana?
Jos palvelimelta ei tule muita PING-pyyntöjä, niin kuulostaa siltä, että ensimmäinen PONG-viesti ei mene perille. Päättyyhän PONG-viesti varmasti merkkeihin \r\n
? Toinen vaihtoehto saattaisi olla, että viesti menee perille, mutta kun botille tulee toinen PING-pyyntö, se ei parsi palvelimelta tulevaa dataa oikein ja lopulta tippuu irkistä. Vaikea sanoa ilman koodia.
Loppuu merkkeihin \r\n
. Koko PING-hommeli epäilyttää minua, sillä botti ei missään vaiheessa yhdistämisen jälkeen ilmoita uudesta PING-pyynnöstä.
Tässä hieman koodia.
# yhdistetään palvelimelle irc = socket.socket() irc.connect((server, port)) irc.send('NICK '+nick+'\r\nUSER '+user+' "" '+server+' :'+real_name+'\r\n') ... while 1: viesti = str(irc.recv(4096)) print viesti if viesti.find("PING") != -1: vList = teksti.split() # en tykkää käyttää merkkijonoja pingNumero = "" for a in range(len(vList)): if vList[a] == 'PING': pingNumero = str(vList[a + 1]) # PING-pyyntö saapuu muodossa PING :numerosarja break irc.send("PONG " + pingNumero + "\r\n") print "PONG " + pingNumero + "\r\n"
Siinä oleelliset kohdat.
Vielä ohjelman tuloste:
NOTICE AUTH :*** Looking up your hostname NOTICE AUTH :*** Checking Ident NOTICE AUTH :*** Found your hostname PING :1851782901 PONG :1851782901 :xs4all.nl.quakenet.org 451 NIMIMERKKI NIMIMERKKI :Register first. :xs4all.nl.quakenet.org 451 NIMIMERKKI NIMIMERKKI :Register first. :xs4all.nl.quakenet.org 451 NIMIMERKKI NIMIMERKKI :Register first. :xs4all.nl.quakenet.org 451 NIMIMERKKI NIMIMERKKI :Register first. :xs4all.nl.quakenet.org 451 NIMIMERKKI NIMIMERKKI :Register first. :xs4all.nl.quakenet.org 451 NIMIMERKKI NIMIMERKKI :Register first. NOTICE AUTH :*** No ident response ***QUAKENETIN Message of the Day YNM.*** :xs4all.nl.quakenet.org NOTICE NIMIMERKKI :on 3 ca 1(4) ft 20(20) :xs4all.nl.quakenet.org 221 NIMIMERKKI +i :*** MODE NIMIMERKKI +i :*** JOIN #KANAVA :xs4all.nl.quakenet.org 353 NIMIMERKKI = #KANAVA :NIMIMERKKEJÄ :xs4all.nl.quakenet.org 366 NIMIMERKKI #KANAVA :End of /NAMES list.
Tämän jälkeen ohjelma ei tulosta enää mitään, ellei joku puhu #KANAVAlla.
Kannattaa pitää mielessä, että recv ei suinkaan aina palauta kokonaista riviä: dataa saattaa tulla kerralla enemmän tai vähemmän. Tämän voi huomioida kokoamalla dataa puskuriin ja käsittelemällä vain kokonaiset rivit:
puskuri = "" while jotain: puskuri += yhteys.recv(4096) rivit = puskuri.split("\r\n") puskuri = rivit.pop() for rivi in rivit: # Tulkitse ja käsittele rivi.
Tämä ei ilmeisesti kuitenkaan ole ongelmasi, koska koodisi pitäisi tulostaa kaikki liikkuvat viestit.
Metabolix kirjoitti:
Kannattaa pitää mielessä, että recv ei suinkaan aina palauta kokonaista riviä: dataa saattaa tulla kerralla enemmän tai vähemmän.
Juu, huomasin. Sen takia PING-pyyntöön vastaaminen käsitellään koodissani niin hankalasti listojen kautta.
EDIT: No kylläpä on omituinen juttu! Kävin kaverin luona kokeilemassa bottiani ja kuin taikaiskusta se toimi moiteettomasti. Mistäköhän tämäkin johtuu... Järjestelmässäni on jotain vikaa ilmeisesti.
Ircin kanssa pelatessa on jokin Wiresharkin kaltainen ohjelma erittäin käytännöllinen, sillä kun saa tutkittua mitä dataa liikkuu serverin ja oman koneen välillä.
Useimmat IRC serverit käyttävät tcp porttia 6667 jolloin wiresharkille kannattaa antaa filtteri "tcp.port==6667", näin muu liikenne ei häiritse tutkimuksia.
Aihe on jo aika vanha, joten et voi enää vastata siihen.