Terve
Millä kielellä saisin helpoiten kännykkään ohjelman, joka ottaa yhteyden tietokoneeseen? Sitten sillä pitäisi myös pystyä netin välityksellä lähettämään tietokoneelle dataa (eli kirjoitetaan kännykällä viesti ja lähetetään tietokoneelle). Tietokoneen pitäisi taas pystyä lukemaan viesti, ja lähettää sille vastaus saadun viestin mukaan.
En tiedä, että onko tämä vaikeaa vai helppoa, mutta joka tapauksessa opettelen vaikka uuden kielen jotta saan ohjelmat valmiiksi.
Esimerkkinä: Kännykällä lähetetään viesti "Moi". Tietokone lähettää vastauksen "Hei!".
Selvennettynä listana kaikki kännykän ja serveri-ohjelman vaatimukset:
Puhelin:
Uskoisin, että toteuttaisin varmaankin ohjelmat C++:lla, koska ymmärrän siitä aikas paljon. En kuitenkaan tiedä, että kännykkäni (E75) tukisi tätä. Yleensä puhelimet eivät tunnu tuollaisia tukea.
Serveri:
Vissiin tuo Java on aika hyvä noita kännykkäsovelluksia varten, siis ainakin Nokian kohdalla. Taitaa Applella olla omat ympäristöt IPhonea varten...
Macro kirjoitti:
Yleensä puhelimet eivät tunnu tuollaisia tukea.
Miten niin? Kyllähän tämä on onnistunut ainakin siitä asti kun ns. "älypuhelimet" tulivat markkinoille...
Kyllähän se esimerkiksi Symbian C++:saa tukee, mutta ohjelmien kehittämisestä sillä voidaan olla montaa mieltä. Tuohon puhelimeen saa asennettua myös Pythonin, joten se on kanssa yksi varteenotettava vaihtoehto.
Luontevimmat valinnat S60-puhelimille ovat Java, Python ja Symbian C++. Suosittelen lämpimästi Pythonia, koska se on noista ainoa, jolla yhtään mikään onnistuu missään määrin helposti. Myös "tavallisten" C- ja C++-kielien ohjelmointi onnistuu periaatteessa "Open C/C++"-systeemien avulla, mutta tästä ei ole nettisovellusten kannalta erityistä hyötyä, koska C:n tai C++:n nykyisiin standardeihin ei tunnetusti sisälly nettitoimintoja.
EDIT: Open C ja C++ sisältävät ilmeisesti myös joitakin hyödyllisiä kirjastoja, joiden kautta myös nettiohjelmointi sittenkin periaatteessa saattaa onnistua. Ainakaan C++:n lisäkirjastotarjonta ei kyllä silti oikein vakuuttanut...
Pythonia osailen vähän, perusasiat menevät jo hyvin. Onnistuuko sillä näistä vaihtoehdoista parhaiten ko. ohjelma? Pääasiassa kysymys olisi nyt, että onko teillä tarpeeksi tuntemusta ko. kielestä että osaatteko neuvoa minua ohjelman toteutuksessa?
Entä, jos teen Pythonilla sen kännykälleni, niin mitenkäs tietokoneelle? Onko järkevintä toteuttaa samalla kielellä?
Muokkaus. Nähtävästi os ehti muokata viestiä, joten osa omastani on vähän turha.
Ei tarvitse toteuttaa samalla kielellä, mutta Python on myös PC-puolella helppoa ja kivaa, joten se kelpaa oikein mainiosti. Nettiohjelmointia kannattaa kokeilla/harjoitella aluksi pelkällä PC:llä ja sen jälkeen vasta puhelimella.
Selvä, eli Pythonilla lähden toteuttamaan. Tuolta Python.orgista latasin Pythonin, mutta sehän on vain tulkki? Tarvitsen siis vielä kääntäjän, mistä saisin hyvän sellaisen?
Pyhton on tulkattava kieli, joten käsittääkseni sitä ei varsinaisesti käännetä. Pyexe:llä sen kyllä saa exe-tiedostoksi...
Miks se pitäis kääntää? Asennat vain tietokoneeseen tulkin. Ja kännykkään pitää asentaa tietenki kanssa tulkki.
Olimpas tyhmä. Taisin ensimmäisen kerran ohjelmoida tällä kielellä kun opin lukemaan ja kirjoittamaan. Siitä on jo jonkin verran aikaa, niin en ihan näitä kaikkia perusasioita muista.
Testasin nyt ihan aluksi, että tulkkini toimii. Kävi niin, että ohjelma vaan vilkahtaa. Miten tämän saa pois?
minkä näköinen ohjelma? Saattaa auttaa jos ajat vaikka komentoriviltä.
Ohjelma, mitä koitin näyttää tältä:
# -*- coding: utf-8 -*- nimi = raw_input("Kirjoita nimesi: "); if len(nimi) > 0: print "Päivää ", nimi else: print "Päivää tuntematon"
Tein tuon ihan kokeilun vuoksi, jotta tiedän tulkin toimivan. Ohjelma kysyy nimen, ja kun sen syöttää niin ohjelma sammuu.
Muokkaus. Tuolta Sourceforgen/Nokian sivuilta ei löytynty tuota Python tulkkia kännykälle. Sourceforgen sivulla sanotaan, että se on siirretty toiseen paikkaan, mutta sitä ei sieltä löydy.
hmm käytätkö python 3? Muistaakseni siin pitää käyttää näin
print("päivää") etc
en kyll oo kylläkään 100% varma tuosta.
(Varmaan olet saman ongelman nähnyt jo C++:n kanssa.) Aja ohjelma komentoriviltä tai IDLEllä, joka tulee Windowsille Pythonin mukana.
Python S60-alustalle löytyy osoitteesta https://garage.maemo.org/projects/pys60/. Ei muuten ollut vaikea löytää vaikkapa Googlesta.
vehkis91: Käytän, mutta tuo ei auttanut.
Metabolix: Kyllä, nyt se toimii.
Legu: Kiitos. Mikä pitäisi ladata? Exe, zip...?
Eihän tuo aiheeseen liity, mutta kyllä ainakin python 3 tutoriaaleissa sanotaan, että kuuluu olla print("teksti"). aikas jännä jos ei toimi.
Macro kirjoitti:
Legu: Kiitos. Mikä pitäisi ladata? Exe, zip...?
sis. Muistaakseni sen joutui signaamaan vielä täällä, että pääsee käsiksi kaikkiin puhelimen ominaisuuksiin.
vehkis91, monet käyttävät yhä Python 2:sta, ja sitä paitsi eihän tässä ollut ongelmana ohjelman toimimattomuus vaan ajoikkunan katoaminen ohjelman päätyttyä, joten vastasit aivan väärään kysymykseen. :)
Kiitos vastauksista. Taidan kysyä toisaalta (Nokialta), miten tämä asennetaan kun ei oikein tullut yhteisymmärrystä.
Sitten siihen ihan aiheeseen, eli serveriin yhdistäminen ja viestien lukeminen, lähettäminen ja vastaanottaminen.
En löytänyt Googlella mitään järkevää, mistä voisin alkaa soveltamaan tätä. Tietääkös joku jonkin hyvän sivun, mistä voisin soveltaa, tai voisiko joku kirjoittaa minulle sovellettavan pätkän? =)
Google tietää esimerkiksi Pythonin dokumentaation.
Macro kirjoitti:
Kiitos vastauksista. Taidan kysyä toisaalta (Nokialta), miten tämä asennetaan kun ei oikein tullut yhteisymmärrystä.
Lataa tuolta sivulta tuo sis -paketti ja lähetä se tänne, että sillä pääsee kaikkiin puhelimen ominaisuuksiin käsiksi (siis, että kirjoittamasi ohjelmat pääsevät niihin käsiksi). Saat sähköpostiin linkin, josta voit ladata allekirjoitetun tiedoston joka asentuu puhelimeen ongelmitta.
Macro kirjoitti:
Tietääkös joku jonkin hyvän sivun, mistä voisin soveltaa, tai voisiko joku kirjoittaa minulle sovellettavan pätkän? =)
Sivut tulivatkin edellä jo, tässä vielä joku koodipätkä (vaikka tämä onkin nähtävästi aika samanlainen kuin tuolla Pythonin dokumentaatiossa):
serveri.py
# -*- coding: utf-8 -*- import socket serveri = (socket.gethostname(), 1337) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(serveri) print("Serveri palvelee osoitteessa %s" % ':'.join(map(str, serveri))) # odotetaan vastapuolta s.listen(1) asiakas, osoite = s.accept() print("%s yhdistetty." % ':'.join(map(str, osoite))) # aloitetaan silmukka while True: data = asiakas.recv(1024) if not data: break print(data) asiakas.send(data) asiakas.close() s.close()
asiakas.py
# -*- coding: utf-8 -*- import socket serveri = ('localhost', 1337) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print("Yhdistetään serveriin %s..." % ':'.join(map(str, serveri))), s.connect(serveri) print("ok") # silmukka while True: mjono = raw_input("Sano jotain: ") if mjono == "LOPETA": break s.send(mjono) data = s.recv(1024) s.close()
Eli serveri tulostaa ruudulle mitä sille lähetettiin ja lähettää kaiken takaisin.
Kannattaa lukea myös täältä, koska puhelimessa menee tekstinsyöttö hieman eri tavalla.
Paljon kiitoksia taas kerran =)
Onko tämä recv(1024) jokin aikakatkaisu-juttu? Kävin syömässä (kesti 10 minuuttia) ja sillä aikaa oli yhteys katkennut.
Sanoit, että serveri lähettää saman takaisin. Sitä se ei kyllä tehnyt.
Funktion recv parametri kertoo, montako tavua vastaanotetaan.
Palvelin kyllä (ainakin koodin perusteella) lähettää datan takaisin, mutta asiakasohjelma ei tulosta sitä ruudulle.
Selvä. =) Empäs älynnyt, kiitos tiedosta.
Koska ääkköset eivät toimineet utf-8 muodossa, niin laitoin koodauksen iso-8859-1:ksi. Kummatkin näyttävät omat viestinsä oikein, mutta serveri ei osaa näyttää niitä oikein. Se kyllä lähettää ne takaisin oikein ja client osaa näyttää vastaan tulleen datan.
Muuten, en löytänyt mistään noista muuttujista clientin ip-osoitetta. Missä se on noista?
Voit käyttää Unicode-tekstejä ja erillistä enkoodausta ja dekoodausta. Olen juuri kirjoittanut aiheesta oppaan, jota tosin ei ole vielä julkaistu. :) Jos et jaksa kokonaan lukea, lue ainakin viimeinen esimerkki ajatuksella.
Kiitos. Vielä sellainen asia, että miten saan serveriohjelman suorittamaan saapuneet viestit komentorivillä (Windows)?
Älä ikinä tee ohjelmaa, joka suorittaa internetistä tulleita autentikoimattomia viestejä suoraan komentorivillä. Tai jos teet, niin älä ainakaan jätä sitä pyörimään...
Empäs ajatellutkaan, että millaista tuhoa se voi tehdä. No, voihan haluamani asiat tehdä toisellakin tavalla, suorittaa ohjelman suoraan.
Kysymys, onko pythonissa jotan open käskyä, jolla saa käynnistettyä ohjelman?
Open käskyllä yleensä avataan tiedosto lukemistaja/tai kirjoittamista varten, ei suorittamista. Ohjelman käynnistäminen eli suorittaminen on eri asia. Mutta ainakin normi Pythonissa on
import os
os.system("ohjelma")
Jep, kiitos.
Miten suoritetaan jotakin tuolla run-paneelissa, tai miksi kutsutaankaan? Nämä toiminnot nähtävästi toimivat vain siellä.
Kyllä kaikkien toimintojen pitäisi toimia yhtä lailla komentorivillä ja run-paneelista. Ohjelma ajetaan joka tapauksessa samalla tavalla, ainoa ero on siinä, minne tuloste ohjautuu. Myöskään os.system ei käytä erityisesti komentoriviä.
Katos kumma, toimihan tuo noin. =)
Miten saan tuosta trilogin serveri versiosta kaivettua viestin lähettäjän esille? Siis, ko. klientin ip-osoitteen.
Entä miten määritettiinkään, että jokin ohjelma käynnistyy aina tietokoneen mukana?
Muokkaus. Koitin pysäyttää ohjelman suorituksen exit() funktiolla, mutta se nähtävästi sulkee sen. Onko Pythonissa jotain vastaavaa funktiota, kuin PHP:n die ja exit?
Sitten vielä sellainen, että miten saan omat virheet Pythonin virheiden tilalle, kun esimerkiksi yhteyttä ei saada serveriin? Nuo Pythonin virheet ovat hyviä kun ohjelmaa kehittää, mutta kun se näytetään käyttäjälle, niin ei.
Macro kirjoitti:
Miten saan tuosta trilogin serveri versiosta kaivettua viestin lähettäjän esille? Siis, ko. klientin ip-osoitteen.
Se löytyy osoite
-tuplen ensimmäisestä alkiosta ja portti toisesta.
Macro kirjoitti:
Muokkaus. Koitin pysäyttää ohjelman suorituksen exit() funktiolla, mutta se nähtävästi sulkee sen. Onko Pythonissa jotain vastaavaa funktiota, kuin PHP:n die ja exit?
Voit nostaa poikkeuksen SystemExit
, jolloin ohjelma sulkeutuu heti.
raise SystemExit("Suljetaan ohjelma")
Edit. Toki exit
toimii myös. Mitä tarkoitit ohjelman suorituksen pysäyttämisellä, jos et kuitenkaan halua sulkea ohjelmaa?
Macro kirjoitti:
Sitten vielä sellainen, että miten saan omat virheet Pythonin virheiden tilalle, kun esimerkiksi yhteyttä ei saada serveriin? Nuo Pythonin virheet ovat hyviä kun ohjelmaa kehittää, mutta kun se näytetään käyttäjälle, niin ei.
Kiitos. Tarkoitin, että ohjelma jäisi siihen kohtaan kun esimerkiksi esimerkki == true.
Koitin tehdä ohjelmaan osan, jolla voi käskeä toista konetta sammumaan.
while True: data = raw_input("Sano jotain: ") if data == "shutdown": print "Sammutetaan kone 20 sekunnin kuluttua" time.sleep(20) os.system("shutdown -r") else: print "Keskeytetään tietokoneen sammuminen" os.system("shutdown -a")
Tämä ei tietenkään toimi, koska time.sleep(20) odottaa ko. kohdassa 20 sekunttia ja sammuttaa koneen sitten. Miten saisin sen toimimaan niin, että se sammuttaisi koneen vasta 20 sekunnin kuluttua, mutta antaisi käyttäjän keskeyttää komennon?
Vaikka tähän tyyliin:
print "Sammutetaan kone 20 sekunnin kuluttua, keskeytä painamalla CTRL+C" try: time.sleep(20) except KeyboardInterrupt: print "Keskeytetään tietokoneen sammuminen" os.system("shutdown -a") else: os.system("shutdown -r")
Keskeytys toimii vain serverin puolelta siis näin. Jos haluat keskeyttää sen asiakkaan puolelta niin itse tekisin varmaankin niin, että pyörittäisin silmukkaa tietyn verran sekunnin välein ja tarkistaisin joka kierroksella onko tullut keskeytysviestiä.
Jesh, kiitos!
Kun käyttäjä lähettää viestin LOPETA (sinun versiosi mukaan), niin yhteys katkeaa. Se menee muuten ihan oikein, mutta en haluaisi serverin lopettavan työtään, vaan että se olisi valmiina seuraavaa kertaa varten.
Laita siis koko ohjelma while-silmukkaan (olennaiset osat, ei tietysti mitään importteja tai funktioiden määrittelyjä tai muuta vastaavaa). Kannattaa varmaan joka tapauksessa jakaa tuota jotenkin järkevämmin.
while True: kuuntele() def kuuntele(): s = socket.socket(...) # ... while True: komento = s.recv(1024) if komento == "LOPETA": break aja(komento) s.close() def aja(komento): # ...
En ihan ymmärtänyt, että miten niinkuin kokonaan tuonne sisään. Onnistuin saamaan sen kysymään kerran viestiä, ja sitten jäämään jumiin...
Muuten, koitin tälläistä, mutta tulos ei ole haluttu. Taustalla näkyy tuollainen tk niminen laatikko, ja sitten vasta tulee tämä haluttu warning-laatikko.
Entä, miten saisin ohjelman "läpinäkyväksi" siten, että ohjelma osaisi vastaanottaa eri asiat clientiltä, mutta ei tulostaisi mitään? Eli, jos lähetän viestin "moi" serverille, niin se ei näy siellä vaan serveri tekee mitä koodissa lukee eikä kerro mitään muille.
Esimerkki 2: Lähetetään viesti "Heippa maailma", ja serverin näytölle tulee pelkkä tuollainen laatikko missä lukee "Heippa maailma".
Jos ymmärsin oikein niin näin:
# odotetaan vastapuolta s.listen(1) asiakas, osoite = s.accept() print("%s yhdistetty." % ':'.join(map(str, osoite))) # aloitetaan silmukka while True: data = asiakas.recv(1024) if not data: break #print(data) #asiakas.send(data) asiakas.close() s.close()
Nyt tuo ei tosin lähetä mitään vastausta clientille.
Macro kirjoitti:
Kun käyttäjä lähettää viestin LOPETA (sinun versiosi mukaan), niin yhteys katkeaa. Se menee muuten ihan oikein, mutta en haluaisi serverin lopettavan työtään, vaan että se olisi valmiina seuraavaa kertaa varten.
Tässä esimerkki serveristä yhdelle asiakkaalle, joka ei sammu kun asiakas lopettaa.
# -*- coding: utf-8 -*- import socket serveri = (socket.gethostname(), 1337) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(serveri) print("Serveri palvelee osoitteessa %s" % ':'.join(map(str, serveri))) # silmukka yhteys = False while True: if not yhteys: # odotetaan vastapuolta s.listen(1) asiakas, osoite = s.accept() yhteys = True print("%s yhdistetty." % ':'.join(map(str, osoite))) else: # datan vastaanottaminen data = asiakas.recv(1024) if not data: asiakas.close() yhteys = False print("Yhteys kohteeseen %s suljettu." % ':'.join(map(str, osoite))) else: # datan käsittely print(data) asiakas.send(data) s.close()
Kiitos taas, trilog. Pienillä muutoksilla sain sen toimimaan hyvin. Vielä kaksi asiaa mietityttää:
Macro kirjoitti:
Entä, miten saisin ohjelman "läpinäkyväksi" siten, että ohjelma osaisi vastaanottaa eri asiat clientiltä, mutta ei tulostaisi mitään? Eli, jos lähetän viestin "moi" serverille, niin se ei näy siellä vaan serveri tekee mitä koodissa lukee eikä kerro mitään muille.
Macro kirjoitti:
Lähetetään viesti "Heippa maailma", ja serverin näytölle tulee pelkkä tuollainen laatikko missä lukee "Heippa maailma".
Mitä tarkoitat läpinäkyvällä? Lähetyksen saat tietenkin estettyä, kun otat send-rivin pois, ja tulostus tapahtuu print-rivillä. Kun poistat molemmat, palvelin ei mitenkään ilmaise (ruudulla tai asiakkaalle) saaneensa viestin. Komentoja ilmeisesti osasit jo ajaa.
Tiesin, että tästä tulisi epäselvyyksiä, siksi laitoin kuvat nettiin: Tässä on väärin toimiva ohjelma, ja tässä se mitä pitäisi saavuttaa.
from Tkinter import * import tkMessageBox tkMessageBox.showwarning("Error!", "Ihihihiihiiii hihiihi :)")
Tk:n pääikkunan saa piiloon, kun luo ja piilottaa sen käsin.
import Tkinter import tkMessageBox root = Tkinter.Tk() root.withdraw() tkMessageBox.showwarning(u"Piilossa!", u"Etpäs löydä!")
Komentorivi-ikkunaa ei käsittääkseni avata, jos skripti ajetaan pythonw:llä pythonin sijaan.
Googlella selvitin.
Metabolix kirjoitti:
Komentorivi-ikkunaa ei käsittääkseni avata, jos skripti ajetaan pythonw:llä pythonin sijaan.
Eli käytännössä on helpointa muuttaa oman kooditiedoston pääte .py -> .pyw
Kannattaa muuten vielä harkita haluaako, että serveri ohjelma hyppäyttelee näytölle ikkunoita jokaiselle viestille erikseen. Joutuu nimittäin kärsivällisyys koetukselle, jos tulee 300 viestiä ja jokainen viesti-ikkuna täytyy sulkea erikseen.
Tee mielummin yksi ikkuna, missä näkyy listassa tulleet viestit ja mahdollisia muita tietoja ja tapahtumia. Voit piilottaa ikkunan ja viestin tullessa tarvittaessa näyttää sen.
Kiitos Metabolix, mutta kai tuon ohjelman saa pienennettyä esimerkiksi tuonne system tray ikoniksi? Löysin tälläisen (Joka ei kuitenkaan toiminut), ja sivulla sanotaan sen olevan helppo tapa Pythonilla, mutta ei siltä vaikuta. Jos ohjelmalle antaa merkkijonon "system tray", niin miten saisin sen silloin pienentyvän tuonne system tray-ikoniksi? Siihen pitäisi saada myös valikko (kuten esimerkissä) josta sen voisi palauttaa normaaliksi ikkunaksi.
Jos system trayhin piilotettu ohjelma vastaanottaa jotakin, niin eikös totta se pysyy system trayssa?
jalski: Nyt et ihan käsittänyt, viestit näkyvät yhdessä ikkunassa, mutta jos lähettää viestin "msgbox title: moi msgbox main: heippa rallaa", niin tulee tuollainen varoitus jonka otsikkona on moi, ja varoituksena on heippa rallaa.
Siitä puheen ollen, että en ihan käsittänyt Python dokumentaation säännöllisten lausekkeiden opasta. Eli, miten saisin msgbox title::n arvon ja asetettua sen muuttujaan, ja saman tuosta msgbox main-kohdasta?
Muokkaus. Jos käyttäjä ottaa yhteyden serveriin, ja sulkee oman klienttinsä "vääräoppisesti" painamalla ruksia, niin silloin serveri antaa virheen:
Traceback (most recent call last): File "C:\Documents and Settings\MMP\Desktop\serveri_.py", line 24, in <module> viesti = asiakas.recv(1024) error: [Errno 10054] An existing connection was forcibly closed by the remote host
ja serveri sammuu.
Entäpä, miten saan "syötettyä" tähtiä, kuten HTML:ssä input type="password"?
Muokkaus 2. Serverin silmukassa on jotain mätää, koska se vastaanottaa käyttäjältä vain kerran salasanan:
while True: if not yhteydessa: yhteys.listen(1) asiakas, osoite = yhteys.accept() print "Kone %s yhdistetty.\n" % ":" . join(map(str, osoite)) if asiakas.recv(1024) == "salasana": yhteydessa = True asiakas.send("allowed") else: yhteydessa = False else: viesti = asiakas.recv(1024) if not viesti: asiakas.close() yhteydessa = False print "Yhteys kohteeseen %s on suljettu." % ":" . join(map(str, osoite)) else: print osoite[0], "sanoo:", viesti asiakas.send("Viesti vastaanotettu.")
Eli, tarkoitus olisi kysyä salasanaa niin monta kertaa kunnes käyttäjä antaa sen oikein. Klientillä kun syötän seuraavasti, niin...
Anna salasana: salakala Salasana väärin! Anna salasana: salasana
... niin ohjelma ei enään reagoi, serveri sulkeutui.
Muokkausaika oli mennyt umpeen, niin laitan uuden viestin.
import re mjono = "title:egg msg:moiiii" m = re.search('(?<=title:)\w+', mjono) i = re.search('(?<=msg:)\w+', mjono) print m.group(0), "\n", i.group(0)
Näin sain poimittua nuo asiat pmiin muuttujiinsa. Nyt pitäisi vielä keksiä jotenkin, että miten selvitä että sisältääkö jokin merkkijono nuo molemmat.
Esimerkki: mjono on "title:vaarin" = ei sisällä, mjono on "title:oikein msg:jee" = sisältää. Mimmoisen if lauseen teen, jos haluan sen sallivan vain viestit joissa on title:jotakin msg:jotakin?
Muokkaus. Sain sen toimimaan, mutta tämä toimii vain, jos siinä on jotakin vikaa, niin tulee error.
import re mjono = "title:Laatikon otsikko msg:Laatikon viesti" m = re.search('(?<=title:)\w+', mjono) i = re.search('(?<=msg:)\w+', mjono) if len(m.group(0)) > 0 and len(i.group(0)) > 0: a = re.search('(?<=title:)\w+', mjono) b = re.search('(?<=msg:)\w+', mjono) print a.group(0), "\n", b.group(0)
Errori, jos ehdot eivät ole tosia:
Traceback (most recent call last): File "C:/Documents and Settings/Mikko/Työpöytä/regex.py", line 8, in <module> if len(m.group(0)) > 0 and len(i.group(0)) > 0: AttributeError: 'NoneType' object has no attribute 'group'
Muokkaus. Sain toimimaan, lisäsin sinne try- ja except-lohkot. Miten saisin säännöllisen lausekkeen sallimaan välilyönnit? Kun se sitten sallii välilyönnit, niin kaiken järjen mukaan m-muuttuja saisi sisällön "Laatikon otsikko msg:Laatikon viesti" ja i-muuttuja "Laatikon viesti", vai mitä?
Toimisko toi?
if re.search('(?<=title:)\w+', mjono): if re.search('(?<=msg:)\w+', mjono): #jotakin
Macro kirjoitti:
Muokkaus. Sain sen toimimaan, mutta tämä toimii vain, jos siinä on jotakin vikaa, niin tulee error.
import re mjono = "title:Laatikon otsikko msg:Laatikon viesti" m = re.search('(?<=title:)\w+', mjono) i = re.search('(?<=msg:)\w+', mjono) if len(m.group(0)) > 0 and len(i.group(0)) > 0: a = re.search('(?<=title:)\w+', mjono) b = re.search('(?<=msg:)\w+', mjono) print a.group(0), "\n", b.group(0)Errori, jos ehdot eivät ole tosia:
Traceback (most recent call last): File "C:/Documents and Settings/Mikko/Työpöytä/regex.py", line 8, in <module> if len(m.group(0)) > 0 and len(i.group(0)) > 0: AttributeError: 'NoneType' object has no attribute 'group'Muokkaus. Sain toimimaan, lisäsin sinne try- ja except-lohkot. Miten saisin säännöllisen lausekkeen sallimaan välilyönnit? Kun se sitten sallii välilyönnit, niin kaiken järjen mukaan m-muuttuja saisi sisällön "Laatikon otsikko msg:Laatikon viesti" ja i-muuttuja "Laatikon viesti", vai mitä?
Lueppas tämä, ja vastaa sen perusteella uudelleen, kiitos =) Eli, m-muuttujan sisältö pitäisi saada tagien title: ja msg: välistä, näin: title:Laatikon otsikko msg:Laatikon sisältö. (Tummennettu kohta jäisi m-muuttujaan)
Macro kirjoitti:
Serverin silmukassa on jotain mätää, koska se vastaanottaa käyttäjältä vain kerran salasanan
Laita salasanakysely omaan silmukkaan, jota pyöritetään niin kauan kunnes salasana on oikein. Nykyinen ratkaisusi ei toimi, koska jos salasana syötetään väärin niin merkkaat yhteyden suljetuksi, vaikka se ei sitä oikeasti ole.
Macro kirjoitti:
Eli, m-muuttujan sisältö pitäisi saada tagien title: ja msg: välistä, näin: title:Laatikon otsikko msg:Laatikon sisältö. (Tummennettu kohta jäisi m-muuttujaan)
>>> import re >>> re.search(ur'title:(.+) msg:(.+)', "title:Laatikon otsikko msg:Laatikon sisältö.").groups() ('Laatikon otsikko', 'Laatikon sis\xc3\xa4lt\xc3\xb6.')
Miten, saanen kysyä? Koska yhteyttä odotetaan tuolla if not yhteys-kohdassa, niin joudun sitä ennen odottamaan uutta yhteyttä salasanan tarkistusta varten. Se ei ole järkevää.
Niin, ja miten pystyn tarkistamaan, että viesti muuttujassa on tuossa säännössä sopivaa tavaraa, kun lähetit tuon lausekkeen? Oma versioni ei toiminut.
# -*- coding: iso-8859-1 -*- import re try: i = re.search(ur'title:(.+) msg:(.+)', "title:Laatikon otsikko msg:Laatikon sisältö.") print i.group(1), "\n", i.group(2) except AttributeError: print "Ei löytynyt merkkijonosta!"
Macro kirjoitti:
Miten, saanen kysyä? Koska yhteyttä odotetaan tuolla if not yhteys-kohdassa, niin joudun sitä ennen odottamaan uutta yhteyttä salasanan tarkistusta varten. Se ei ole järkevää.
Tarkista ohjelmasi logiikka: jos serveri tai asiakas itse ei sulje sockettia, niin et joudu odottelemaan uutta yhteyttä vaan voit vastaanottaa socketista niin kauan kunnes asiakas katkaisee yhteyden tai vastaanotettu syöte on mieleisesi.
Macro kirjoitti:
Miten, saanen kysyä? Koska yhteyttä odotetaan tuolla if not yhteys-kohdassa, niin joudun sitä ennen odottamaan uutta yhteyttä salasanan tarkistusta varten. Se ei ole järkevää.
Otat tarkistuksen pois yhteyden muodostamisesta ja laitat sen tuonne alas, missä käsitellään data. Eli annat asiakkaan muodostaa yhteyden serveriin ja ensimmäinen data mitä siltä odotat on salasana.
Macro kirjoitti:
Niin, ja miten pystyn tarkistamaan, että viesti muuttujassa on tuossa säännössä sopivaa tavaraa, kun lähetit tuon lausekkeen? Oma versioni ei toiminut.
Millä tavalla se ei toimi? Minulla toimii ihan hyvin, tulostaa siis:
Laatikon otsikko Laatikon sisältö.
trilog kirjoitti:
Macro kirjoitti:
Miten, saanen kysyä? Koska yhteyttä odotetaan tuolla if not yhteys-kohdassa, niin joudun sitä ennen odottamaan uutta yhteyttä salasanan tarkistusta varten. Se ei ole järkevää.
Otat tarkistuksen pois yhteyden muodostamisesta ja laitat sen tuonne alas, missä käsitellään data. Eli annat asiakkaan muodostaa yhteyden serveriin ja ensimmäinen data mitä siltä odotat on salasana.
Äh, olimpa tyhmä! Siellähän sitä voi pyörittää.
trilog kirjoitti:
Macro kirjoitti:
Niin, ja miten pystyn tarkistamaan, että viesti muuttujassa on tuossa säännössä sopivaa tavaraa, kun lähetit tuon lausekkeen? Oma versioni ei toiminut.
Millä tavalla se ei toimi? Minulla toimii ihan hyvin, tulostaa siis:
Laatikon otsikko Laatikon sisältö.
Niin, kyllä se tulostaakin. Ajattelin, että minkälaisen if-lauseen saisin tarkistamaan onko viestissä noin kirjoitettu. Keksin jo kuitenkin, että miten teen sen.
#! /usr/bin/python import gtk import egg.trayicon # egg == python-gnome2-extras def callback(widget, ev): print "Button %i pressed!" % ev.button tray = egg.trayicon.TrayIcon("TrayIcon") box = gtk.EventBox() label = gtk.Label("Click Me!") box.add(label) tray.add(box) tray.show_all() box.connect("button-press-event", callback) gtk.main()
Tälläisen löysin. Tällä pitäisi saada ohjelma system trayhin piiloon, mutta en tiedä sitten. Tarkoitus olisi, että ohjelma vastaanottaisi siis niitä viestejä ja suorittaisi koneellani ne. Ohjelma pysyisi myös tieltä pois, ja toimisi system trayssa.
Äskeinen koodi taitaa toimia vain Linuxeissa? Kuvitellaan, että tässä on koodini:
# -*- coding: utf-8 -*- import socket serveri = (socket.gethostname(), 1337) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(serveri) #print("Serveri palvelee osoitteessa %s" % ':'.join(map(str, serveri))) # silmukka yhteys = False while True: if not yhteys: # odotetaan vastapuolta s.listen(1) asiakas, osoite = s.accept() yhteys = True #print("%s yhdistetty." % ':'.join(map(str, osoite))) else: # datan vastaanottaminen data = asiakas.recv(1024) if not data: asiakas.close() yhteys = False #print("Yhteys kohteeseen %s suljettu." % ':'.join(map(str, osoite))) else: # datan käsittely #print(data) asiakas.send(data) s.close()
Miten saan tuon ohjelman toimimaan niin, että se näkyy system trayssa vain? Olen pohtinut sitä samaa eri kielillä jo monta vuotta.
Kukaan ei siis tiedä? Höh!
Jos serverillä on seuraavanlainen koodi:
try: haku = re.search(ur'title:(.+) msg:(.+)', viesti) otsikko = haku.group(1) sisalto = haku.group(2) root = Tkinter.Tk() root.withdraw() tkMessageBox.showwarning(otsikko, sisalto) except AttributeError: example = ""
Sitten klientiltä lähetetään viesti title:jotain msg:jotain, niin serverille tulee oikein tuollainen varoitus. Ongelmana on se, että serveri on jumissa, kunnes painetaan ok. Se ei ole kiva, koska silloin se ei vastaanota mitään muuta, ja klientti jumittuu samassa. Miten tämän korjaisin?
Viesti-ikkunoiden on yleensä tarkoituskin toimia niin. Voit toki näyttää laatikon toisessa säikeessä, mutta silloin se säie taas jumittuu, kunnes laatikko on hoidettu. Koska ominaisuus ei vaikuta kovin järkevältä, kannattaa ehkä miettiä, mikä on sen tarkoitus ja miten sen voisi toteuttaa järkevämmin. Esimerkiksi jalskin ehdotus olisi minusta hyvä: tulosta viestit jollain tavalla ohjelman pääikkunaan. Tässä joutuisit opettelemaan Tk:n käyttöä hieman enemmän, mutta lopputulos olisi sata kertaa parempi.
Kuinka toisessa säikeessä? Oikeastaan, kun tässä tein eilen vielä tuota ohjelmaa illalla, niin tuli mieleen että ei sillä olisikkaan väliä että jää jumiin ko. kohtaan. Jossain kohtaa se olisi hyvä.
Kysyn vielä, että miten saan ohjelman piilotettua system trayhin?
Macro kirjoitti:
Kuinka toisessa säikeessä? Oikeastaan, kun tässä tein eilen vielä tuota ohjelmaa illalla, niin tuli mieleen että ei sillä olisikkaan väliä että jää jumiin ko. kohtaan. Jossain kohtaa se olisi hyvä.
Kysyn vielä, että miten saan ohjelman piilotettua system trayhin?
Tarkoittaa, että luot oman säikeen (=thread) käsittelemään viesti-ikkunan, jolloin muu ohjelma jatkaa toimintaansa. Ohjelmoit vissiin Windows alustalle? xHarbourilla ohjelmoidessani system tray ikoni on nimellä NotifyIcon.
Voisit tutustua: http://www.codeplex.com/wikipage?ProjectName=IronPython
ja http://andrzejonsoftware.blogspot.com/2007/01/
Okei, en olekkaan kuullut siitä NotifyIcon nimityksestä. Kiitos tiedosta!
Tuo Codeplex sivu on aika sekava (En saanut käsitystä asiasta), niin vilkaisin tuonne blogiin. Kopioin koodin, ja siistin sitä vähän.
IDLE sanoo, että "ImportError: No module named clr". Miten korjaisin asian?
(Koodi siltä varalta, että joku haluaa kokeilla. Kopioimalla sen tuolta, kaikki rivinvaihdot ovat päin puuta)
import clr clr.AddReference("System.Windows.Forms") clr.AddReference("System.Drawing") from System.Drawing import Icon from System.Windows.Forms import (Application, ContextMenu, MenuItem, NotifyIcon, Timer) class Main(object): def __init__(self): self.initNotifyIcon() timer = Timer() timer.Interval = 60000 timer.Tick += self.onTick timer.Start() def initNotifyIcon(self): self.notifyIcon = NotifyIcon() self.notifyIcon.Icon = Icon("test.ico") self.notifyIcon.Visible = True self.notifyIcon.ContextMenu = self.initContextMenu() def onTick(self, sender, event): self.notifyIcon.BalloonTipTitle = "Hello, I'm IronPython" self.notifyIcon.BalloonTipText = "Who are you?" self.notifyIcon.ShowBalloonTip(1000) def initContextMenu(self): contextMenu = ContextMenu() exitMenuItem = MenuItem("Exit") exitMenuItem.Click += self.onExit contextMenu.MenuItems.Add(exitMenuItem) return contextMenu def onExit(self, sender, event): self.notifyIcon.Visible = False Application.Exit() if __name__ == "__main__": main = Main() Application.Run()
Muokkaus. Tuo taitaakin olla Javaa, vai?
Ei ole Javaa ei...
Tuo esimerkki on IronPythonille, mikä toimii .NET:in ja Silverlightin päällä. Suosittelin sitä, kun kerran ohjelmoit Windows käyttöjärjestelmälle.
Asenna IronPython siitä ensimmäisestä antamastani linkistä ja kokeile ajaa esimerkki koodi sillä.
Testasin muuten esimerkin toiminnan juuri äsken ja se toimii.
IronPython on "Python.Net". Käytännössä rajoitat sillä saman tien ohjelmasi toiminnan Windowsiin. Taas kerran jalski innostui ehdottelemaan aivan aiheen ohi uusia työkaluja, vaikkei vielä ole tutkittu edes vanhojen mahdollisuuksia kunnolla.
(Java sitten taas on syntaksiltaan melkein C++:n näköistä eli hyvin kaukana Pythonista.)
Mieti taas, minkä arvoinen tuo tray icon lopulta, niin voit sitten päättää, kannattaako sen takia vaihtaa ohjelmointikieltä tai -ympäristöä vai voisitko kehittää jonkin vaihtoehtoisen ratkaisun. Minusta on aivan tyhmää hypellä ympäristöstä toiseen yhden pienen ominaisuuden takia, varsinkin silloin, kun ohjelma on tulossa vain omaan käyttöön ja ehkä suurempi tarkoitus on vain opetella ohjelmointia.
Kiitokset vastauksista.
jalski: Miten ajoit sen? Liitin ohjelman sinne, mutta valittaa vääränlaisesta syntaksista. Vai, kuuluuko sille antaa polku tiedostoon?
Metabolix: Sillä ei nyt tässä vaiheessa ole väliä, että toimiiko se Windowsissa vai ei. Vain Windowseja käytössä.
Oikeastaan tray icon on aika tärkeä lopputuloksen kannalta.
Metabolix kirjoitti:
kannattaako sen takia vaihtaa ohjelmointikieltä tai -ympäristöä vai voisitko kehittää jonkin vaihtoehtoisen ratkaisun.
Ei tässä nyt kai ohjelmointikieltä tarvitse vaihtaa?
Jos IronPythonin polut on asetettu kohdilleen, niin suoritat vain:
ipy tiedosto.py
Esimerkin tarvitsee löytää ikonitiedosto test.ico toimiakseen.
IronPython on kohtuullisen yhteensopiva Pythonin kanssa. Ainakin tuo serveri-ohjelmasi toimii suoraan sellaisenaan.
Missä nämä ns. "polut" sijaitsevat, ja mitä ne ovat oletuksena? Kyllä, minulla on tuo test.ico.
Suorita vaikka komentoriviltä: set path=%path%;"c:\Program Files\IronPython 2.6"
Mene komentoriviä edelleen käyttäen hakemistoon, missä on koodi -ja ikoni tiedosto. Tämän jälkeen toimit edellisen viestini ohjeiden mukaan.
Taidan noudattaa Metabolixin neuvoa, ja opetella ensin ihan perusasiat - sitten vasta ottaa kirjastoja mukaan.
Kysyisin sellaista vielä, että nähtävästi serveri ja klientti osaavat vastaanottaa skandinaaviset aakkoset oikein, mutta ei näyttää. C/C++:ssa on nämä \x84... merkinnät ääkkösille. Ajattelin, että datasta muuttaisin replace-funktiolla ääkköset näiksi ja tulostaisin sitten. Vai onko Pythonissa tälläisiä?
Ohjelmien merkistö on ISO-8859-1, eikös tämän pitäisi osata näyttää ääkköset?
Luepa uudestaan sitä linkittämääni merkistöopasta, siinä puututaan juuri näihin asioihin. Avain kaikilla toimivaan ohjelmaan on Unicode-tekstin käyttö eli u-kirjain jokaisen tekstivakion alussa. Kun dataa siirretään verkossa, se pitää kuitenkin enkoodata jotenkin, esimerkiksi UTF-8-enkoodauksella.
Eli, minun kannattaisi muuttaa ohjelmien merkistö muotoon cp850, jota Windowsin komentorivi käyttää? Koitin myös käyttää tuota u-merkintää merkkijonojen edessä: Se auttoi, kunnes skandinaavisia merkkejä lähetti serverille. Nähtävästi ohjelmani ei osaa vastaanottaa ääkkösiä.
Minulle ei käynyt ihan selväksi oppaastasi, että miten muuttuja muutetaan unicode-muotoon. Viesti tulee serverille, ja asetetaan viesti-muuttujaan. Miten saan siis muutettua viesti-muuttujan unicode-muotoon?
Toivottavasti äskeisen perusteella olen oikeilla jäljillä, enkä ihan metsässä.
Muokkaus. Nähtävästi ääkköset toimivat halutussa paikassa (komentorivillä), mutta tkMessageBoxissa ne eivät toimi vielä, vaan muuttuvat näiksi neliöiksi.
Lisäyksenä vielä, että minulla on ongelma ajan tulostuksen kanssa: strftime("%H:%M:%S", gmtime()) tulostaa ajan GMT 0-ajassa. Miten saisin asetettua aikavyöhykkeen GMT +2?
Viimeisessä esimerkissä näytetään muunnokset: tiedostosta luetaan UTF-8-dataa, joka muutetaan decode-funktiolla Unicode-tekstiksi, ja tallennusvaiheessa taas muutetaan encode-funktiolla tekstit UTF-8-muotoon. Ohjelman sisällä kannattaa aina käsitellä Unicode-tekstejä, ja vain siinä tapauksessa, että johonkin tarvitaan muuta (esimerkiksi verkossa lähetettäväksi tai tiedostoon tallennettavaksi), muutetaan teksti oikeaan muotoon. Oppaassa keskitytään lähinnä siihen, miten Unicode-tekstin saa muutettua tulostusta varten oikeaan merkistöön (sys.stdout.encoding) ja vastaavasti miten luetun syötteen saa Unicode-tekstiksi. Tulostusasia koskee sinuakin. Tk:lle voi ehkä antaa suoraan Unicode-tekstejä.
Jep, siinä se! Nyt sekin asia tuli opittua (muuttuja.decode("merkistö")). =) Yksi asia minua vaivaa vielä: Tuo aika. Kannattaako minun ottaa tunnit, minuutit ja sekunnit omiin muuttujiinsa, plussata tunnit-muuttujaan 2 (Jolloin GMT 0 = GMT +2) ja tulostaa niiden väliin pisteet?
Miten saisin suoraan ajan tähän "oikeaan aikaan", GMT +2:een?
Ratkaisin aikaongelmani jo. Nyt kuitenkin on todella kummallinen tilanne: Kun ensimmäisen kerran otin yhteyden serveriin edellispäivänä, niin clientin portti oli jokin 1200-1250. Nyt kun olen muodostellut yhteyksiä, niin klientti ottaa yhteyden jo portista 2135! Eikö ohjelma vapauta porttia? Tämä pitää minusta korjata heti, osa ohjelmistani on jo ehtinyt valittaa kun ko. ohjelman portti on varattu.
Tuota pohdittaessa, kysyn vielä Pythonin yhteyksistä MySQL-tietokantaan.
En löytänyt mistään esimerkkiä, että miten Pythonilla voi yhdistää tietokantaan, lukea sieltä tietoa ja kirjoittaa sinne. Toivoisin, että täältä löytyisi apua.
Empäs keksinytkään noin helppoja hakusanoja :D
Mureakuhassa sanottiin, että tarvitsee asentaa Pythoniin ne moduulit. Latasin exen täältä: http://sourceforge.net/projects/mysql-python/, mutta asennusohjelma sanoo "Python version 2.5 required, witch was not found in the registry.". Siis, versiota 2.5 ei ole minulla, nähtävästi oli 2.6. SorseForgen sivuilla sanotaan, että se kelpaisi myös versiolla 2.6, mutta ei. Mistä saan siis oikean version?
Muokkaus. Löysin oikean version, mutta saan virheen seuraavasta ohjelmasta:
# -*- coding: cp850 -*- import MySQLdb db = MySQLdb.Connection(host="localhost", user="root", passwd="", db="foorumi") # Run a MySQL query from Python and get the result set db.query("SELECT * FROM alueet") r = db.store_result() # Iterate through the result set # Example calls back up to 100 rows for row in r.fetch_row(100): print row
Traceback (most recent call last): File "C:\Documents and Settings\Mikko\Työpöytä\mysql.py", line 3, in <module> import MySQLdb File "C:\Python\lib\site-packages\MySQLdb\__init__.py", line 19, in <module> import _mysql ImportError: DLL load failed: Määritettyä osaa ei löydy.
Miten serveri-ohjelman toteutus sujuu? Mihin ratkaisuun päädyit käyttöliittymän suhteen: Tk-pohjainen, vai joku muu?
Toteutin iltapuhteena Chat Serverin. Koodin pituudeksi tuli n. 450 riviä ja toteutettuna on käyttäjänimen asetus, kaikille suunnatut viestit, yksityisviestit ja yhteystapahtumien välitys käyttäjille.
Chat Serverin ulkoasun toteutin käyttäen Tk:ta. Ulkoasu koostuu kolmesta osasta: käyttäjälista (nimi tai ip-osoite), yhteystapahtumat ja kaikille suunnatut viestit.
jalski kirjoitti:
Miten serveri-ohjelman toteutus sujuu? Mihin ratkaisuun päädyit käyttöliittymän suhteen: Tk-pohjainen, vai joku muu?
Ohjelmassa voi toteuttaa TkMessageBoxin, mutta viestit tulostuvat pääikkunaan eli komentoriville.
Miksei ylläoleva MySQL-testi toimi? Latasin täältä http://home.netimperia.com/files/misc/MySQL-python-1.2.2.win32-py2.6.exe MySQL 2.6 versiolle, mutta saan tuon virheen. Mitä tulee tehdä? Onko koodi vioittunut, vai onko MySQL-tuki puutteellinen?
Tarvitset MySQL:n DLL-tiedoston, luultavasti libmysql.dll. Se pitää sitten aina (Windowsissa) kuljettaa ohjelman mukana.
En löytänyt, että mihin se pitäisi laittaa. Koitin laittaa sen samaan hakemistoon ohjelman kanssa, mutta se ei auttanut.
Oikea DLL taitaakin olla _mysql.dll. Tuon varmasti kuuluisi sisältyä pakettiin. En löytänyt ainakaan pikaisesti valmista latauspaikkaa, mutta ainahan sen voi kääntää itse. Lähdekoodi on C:tä ja löytyy SourceForgen paketeista, ja kääntämiseen tarvitaan lisäksi ainakin Pythonin ja MySQL:n C-rajapintojen otsikkotiedostot, ehkä muutakin.
Aihe on jo aika vanha, joten et voi enää vastata siihen.