Tkinter + Socket

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo,

    ich habe vor ein Programm zu schreiben, das einmal ein Fenster (Tkinter) auf
    meinem PC hat und ein anderes, dass auf dem PI läuft. Die Kommunikation
    soll sowohl von PI zu PC wie auch anders herum über einen TCP socket laufen.

    Das Problem ist nun, dass das Warten auf eine Nachricht das Programm blockiert (wodurch vor allem das Tkinter Fenster nicht funktioniert). Es geht zwar grundsätzlich von PC zu PI aber nicht umgekehrt. Dies sollte aber unabhängig voneinander möglich sein.

    Ich habe im Internet etwas von nicht blockierenden socket gelesen, finde aber kein gutes Beispiel, wie man diesen Benutzt.

    MfG ProfDrFisch


    Ein "Gefällt mir" oder eine Bewertung wäre nett. :danke_ATDE:

    Support per [PM]

    • Offizieller Beitrag

    Hast einen du Server und einen Client oder 2 server und 2 clients? Wenn überhaupt würde ich den Socketserver einzeln laufen und beide tkinter Anwendungen als Clients agieren lassen...und selbst das gefällt mir nicht wirklich ;)

  • Das TKinter Fenster ist nur auf meinem PC, das Programm auf dem PI soll in der Konsole laufen.
    Das Programm dient momentan nur Testzwecken, hat also noch keinen praktischen Nutzen.


    Client:

    Server:

    Der Server sendet momentan nur die an ihn gesendete Nachricht zurück und das TKinter Fenster schreib diese dann in das Textfeld.

    Das Problem ist nur, dass ich das so nicht nutzen kann, um immer die neusten Sensorwerte zu haben, sondern diese immer aktualisieren müsste.

    Es wäre vom Prinzip her egal, ob auf beiden ein Server und ein Client läuft oder nur auf dem PI ein Server.

    MfG ProfDrFisch


    Ein "Gefällt mir" oder eine Bewertung wäre nett. :danke_ATDE:

    Support per [PM]

    Einmal editiert, zuletzt von ProfDrFisch (2. Februar 2015 um 20:44)

  • Ja, genau (sind zwar ein Paar Werte, aber das ist nicht das Problem).
    Der bei sollte aber gleichzeitig auf Befehle reagieren können, die ich
    zu im sende. Und das Fenster sollte halt auf meinem PC und nicht auf
    dem PI laufen.


    Ein "Gefällt mir" oder eine Bewertung wäre nett. :danke_ATDE:

    Support per [PM]

  • Du möchtest also nur 1x TKinter haben? Auf dem PI läuft ein SocketServer und dein TKinter-Client ruft die Daten ab? Oder soll der TKinter auch auf dem PI laufen und zB über Xming als Fenster aufgehen? ;)

    Nun ich denke du hast 1-2 kleine Fehler:

    Code
    s.sendto( e1.get(), (Ziel,Port) )

    solltest du ändern in:

    Code
    s.sendall( e1.get() + "\n" )

    Im Server.py machst du es einfach so das der Request eine Anweisung ausführt und dessen Wert dann zurück schickt:
    [code=php]
    import socket

    TCP_IP = '127.0.0.1'
    TCP_PORT = 5000
    BUFFER_SIZE = 4096


    def getTemp():
    with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f:
    CPUtemp = int(float(f.readline().split()[0]))
    CPUtemp = round((CPUtemp/1000.0), 2)
    return CPUtemp

    def getUptime():
    with open('/proc/uptime', 'r') as f:
    uptime_seconds = float(f.readline().split()[0])
    uptime = str(timedelta(seconds = uptime_seconds))
    return uptime

    def getPiRAM():
    with open('/proc/meminfo', 'r') as mem:
    tmp = 0
    for i in mem:
    sline = i.split()
    if str(sline[0]) == 'MemTotal:':
    total = int(sline[1])
    elif str(sline[0]) in ('MemFree:', 'Buffers:', 'Cached:'):
    tmp += int(sline[1])
    free = tmp
    used = int(total) - int(free)
    usedPerc = (used * 100) / total
    return usedPerc

    try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((TCP_IP, TCP_PORT))
    s.listen(1)
    conn, addr = s.accept()
    print 'Connection address:', addr
    while 1:
    data = conn.recv(BUFFER_SIZE).strip()
    if data:
    reqdata = ""
    print "received data:", data
    if data == "pitemp":
    reqdata = str(getTemp())
    elif data == "piram":
    reqdata = str(getPiRAM())
    else:
    reqdata = "UNKNOWN!"
    conn.send(reqdata + "\n")
    except (KeyboardInterrupt, SystemExit):
    print("Schliesse Server..")
    s.close()
    conn.close()
    [/php]


    So kann der Client über die selbe Verbindung mehrere Anfragen stellen.
    Für regelmäßige Anfragen würd ich das über threading und davon Timer machen

    //EDIT:

    Hier, bitte sehr - viel Erfolg :angel:

    "Client.py"

    [code=php]import socket
    from Tkinter import *
    import threading

    Ziel = "127.0.0.1"
    Port = 5000

    HF = Tk()
    HF.title("Steuerung")
    HF.geometry("400x500")

    def TimedRequest(when, what):
    global timed
    when = float(when)
    what = str(what)
    if not conn:
    Verbinden()
    conn.sendall( what + "\n" )
    received = conn.recv(4096)
    Text1.configure(state=NORMAL)
    Text1.insert(END, (received))
    Text1.configure(state=DISABLED)
    timed = threading.Timer( when, TimedRequest, [when, what] )
    timed.start()

    def Verbinden():
    global conn, timed
    conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
    conn.connect((Ziel, Port))
    Status.configure(text="Verbunden", fg="green")
    timed = threading.Timer( 2.0, TimedRequest, ["2.0", "pitemp"] )
    timed.start()
    except:
    Status.configure(text="Failed", fg="red")
    timed.cancel()

    def Trennen():
    conn.close()
    timed.cancel()
    Status.configure(text="Getrennt", fg="red")
    Text1.configure(state=NORMAL)
    Text1.delete("1.0", END)
    Text1.configure(state=DISABLED)

    def Senden():
    conn.sendall( e1.get() + "\n" )
    received = conn.recv(4096)
    Text1.configure(state=NORMAL)
    Text1.insert(END, (received))
    Text1.configure(state=DISABLED)

    Status = Label(HF)
    Status.configure(text="Getrennt", fg="red")
    Status.grid(row=0, column=2)
    e1 = Entry(HF, width=20)
    e1.grid(row=1, column=4)
    but1 = Button(HF, text="Verbinden", width=10, command=Verbinden)
    but1.grid(row=1, column=1)
    but2 = Button(HF, text="Trennen", width=10, command=Trennen)
    but2.grid(row=1, column=2)
    but3 = Button(HF, text="Senden", width=10, command=Senden)
    but3.grid(row=1, column=3)

    Text1=Text(HF, height=22, width=25)
    Text1.configure(state=DISABLED)
    Text1.grid(row=2, column=1, columnspan=3)

    try:
    mainloop()
    except (KeyboardInterrupt, SystemExit):
    print("Schliesse Programme..")
    timed.cancel()
    except:
    timed.cancel()[/php]

    "Server.py"

    [code=php]import socket

    TCP_IP = '127.0.0.1'
    TCP_PORT = 5000
    BUFFER_SIZE = 4096


    def getTemp():
    with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f:
    CPUtemp = int(float(f.readline().split()[0]))
    CPUtemp = round((CPUtemp/1000.0), 2)
    return CPUtemp

    def getUptime():
    with open('/proc/uptime', 'r') as f:
    uptime_seconds = float(f.readline().split()[0])
    uptime = str(timedelta(seconds = uptime_seconds))
    return uptime

    def getPiRAM():
    with open('/proc/meminfo', 'r') as mem:
    tmp = 0
    for i in mem:
    sline = i.split()
    if str(sline[0]) == 'MemTotal:':
    total = int(sline[1])
    elif str(sline[0]) in ('MemFree:', 'Buffers:', 'Cached:'):
    tmp += int(sline[1])
    free = tmp
    used = int(total) - int(free)
    usedPerc = (used * 100) / total
    return usedPerc

    try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((TCP_IP, TCP_PORT))
    s.listen(1)
    conn, addr = s.accept()
    print 'Connection address:', addr
    while 1:
    if conn:
    data = conn.recv(BUFFER_SIZE).strip()
    if data:
    reqdata = ""
    print "received data:", data
    if data == "pitemp":
    reqdata = str(getTemp())
    elif data == "piram":
    reqdata = str(getPiRAM())
    else:
    reqdata = "UNKNOWN!"
    conn.send(reqdata + "\n")
    except (KeyboardInterrupt, SystemExit):
    print("Schliesse Server..")
    s.close()
    conn.close()
    [/php]

    Allerdings funktioniert Server.py nur solange die Verbindung bestehen bleibt. Wird die Verbindung getrennt kann keine erneute hergestellt werden. Für dieses Problem würde ich threading verwenden ;)

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!