Sock hängt sich auf

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Crazy-Sonic
User
Beiträge: 1
Registriert: Sonntag 3. April 2016, 18:53

Hallo liebe Pythonfreunde,

Ich bastele grade an einem "Gateway" für Sensordaten auf einem Raspberry Pi, mein Code läuft auch bis auf dem Socket.
Allerding finde ich den fehler nicht. Vieleicht kann mir jemand helfen, ich bin noch neu in Python vieleicht kann mir ja
auch jemand noch Tips geben zu Optimirung. :idea:

Hardware:
Raspberry Pi 1
Geigerzähler an ttyAMA0 der jede Sekunde den Aktuellen Wert schickt.( Optional USB tauglich, war mir aber zu kompliziert :oops: )
SPS über Ethernet angekoppelt.

Software:
Das Script soll die Daten von der Seriellen Schnittstelle auf dem Ethernet an Port 10001 bereitstellen.
Es sollen noch weitere Sensoren folgen ( Temperatur, Luftfeuchte, usw ).

Hier der Code:

Code: Alles auswählen

#! /usr/bin/python3
import sys, tkinter, serial, time, _thread, socket, platform

#Sytem Variables
global hostname
global tcp_port
global tcp_ip
global ser
global act_rad
global buffer_size

tcp_ip = "192.168.2.50"
tcp_port = 10001
buffer_size = 1024

												#Serielle Schnittstelle Öffnen und das empfangene in eine Varriable Schreiben
def openser():
    ser = serial.Serial()
    ser.port = "COM1"
    ser.baudrate = 9600

    ser.open()
    if ser.isOpen():
        print ("Serial Port Open!!")
        while ser.isOpen:
             act_rad = float(ser.readline())/100
    else:
        print ("Error!!")


								#Socket Öffnen und auf Port 10001 Lauschen bis das Sendecommand von SPS kommt ("send_A1")
def opentcp():
    try:
        while 1:
            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)
                 if not data: break

                 else:
                     print (data)
                     if data == b'send_A1' or data == b'send_A1\r\n':
                        conn.send(bytes("A1=" + str(act_rad) + ",\r\n", 'utf-8'))

        conn.close()
    except:
        print ("Verbindung vom Remote Beendet")							#Wenn Sock beendet wird, neu Starten.
        tcpdata_threadID = _thread.start_new_thread(opentcp, ())


tcpdata_threadID = _thread.start_new_thread(opentcp, ())
openser()


Es wäre schön wenn mir jemand Helfen könnte,

mit Freundlichen Grüßen
Crazy
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@Crazy-Sonic: was heißt "läuft nicht"? Gibt es eine Fehlermeldung?

Vergiss dass es global gibt (auf Modulebene hat das sowieso keinen Einfluß), per Konvention werden Konstanten komplett in GROSSBUCHSTABEN geschrieben.
Benutze keine Module, die mit einem Unterstrich beginnen. Statt _thread gibt es threading.
Importiere nur Module, die Du auch brauchst.
Ein Funktionsobjekt (ser.isOpen) evaluiert immer zu True.
Kommuniziere mit Threads über entsprechende Datenstrukturen, z.b. Queues.
TCP ist ein streaming Protokoll, benutze makefile um wirkliche Fileobjekte zu bekommen.
BlackJack

@Crazy-Sonic: Laut Style Guide for Python Code sollte pro Zeile nur ein Modul import werden, damit es übersichtlicher bleibt, und Änderungen eine eigene Zeile betreffen.

Der `isOpen()`-Test, den Sirius3 anspricht, wäre auch mit Aufruf der Methode nicht sinnvoll, denn es gibt nirgends einen `close()`-Aufruf, also wird auch der Aufruf dieser Testmethode immer `True` ergeben. Auch der erste Aufruf macht keinen Sinn, denn wenn das mit dem `open()` nicht klappt, dann würde dieser Aufruf bereits eine Ausnahme auslösen und man käme nicht zu dem Test.

Wenn man gleich nach dem Erstellen die `open()`-Methode aufruft, kann man die Angaben von Port und Baudrate auch gleich beim Erstellen erledigen und sich so einige Zeilen Quelltext sparen.

Die Einrückung sollte vier Leerzeichen pro Ebene betragen und nicht irgendwas zwischen 3 und 5 (jeweils inklusive). Wie machst Du das? Betätigst Du tatsächlich mehrfach die Leertaste? Jeder vernünftige Editor lässt sich so konfigurieren, dass die Tabulatortaste vier Leerzeichen einrückt.

Zwischen Funktionsname und öffnender Klammer für den Aufruf wird üblicherweise kein Leerzeichen gesetzt.

Namen sollten dem Leser vermitteln wofür der Wert dahinter im Programm steht und nicht aus irgendwelchen kryptischen Verkürzungen bestehen bei denen man erst einmal raten muss was die bedeuten mögen. `openser()` macht mehr als nur eine serielle Verbindung zu öffnen und `opentcp() mehr als eine TCP-Verbindung zu öffnen. `act_rad`? Wenn ich raten müsste `actual_radiation` und damit wahrscheinlich falsch übersetzt, denn „actual” heisst „tatsächlich“ und nicht „aktuell“.

Das ``try``/``except`` ist sinnfrei bis gefährlich. Da behandelt jede Ausnahme, auch Programmierfehler und Ausnahmen mit denen Du gar nicht rechnest in dem sie einfach ignoriert werden. Und die Ausgabe ist in den meisten Fällen falsch, denn wenn die Verbindung von der Gegenseite (regulär) abgebrochen wird, dann hat das gar keine Ausnahme zur Folge. Was von der Behandlung jeglicher Ausnahmen zum Beispiel hier ”verschluckt” wird ist die Ausnahme die durch den nicht definierten Namen `act_rad` ausgelöst wird.

Das erneute Starten eines Threads sollte nicht von der Funktion selbst aus passieren sondern ausserhalb.

Statt 0 und 1 sollte man `False` und `True` verwenden wenn man Wahrheitswerte meint.

Die äussere ``while``-Schleife ist dort falsch platziert, denn man will ja das gleiche Server-Socket wiederverwenden und nicht immer neu binden wenn man das vermeiden kann.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
from __future__ import absolute_import, division, print_function
import socket
from threading import Thread

from serial import Serial

TCP_IP = "192.168.2.50"
TCP_PORT = 10001
BUFFER_SIZE = 1024


def read_geiger_counter():
    connection = Serial('COM1', 9600)
    print('Serial Port Open!')
    for line in iter(connection.readline, None):
        # 
        # BUG This assignment is using a local name.  Needs OOP to solve this.
        # 
        radiation = float(line) / 100


def serve_radiation_values():
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((TCP_IP, TCP_PORT))
    server_socket.listen(1)
    while True:
        sock, address = server_socket.accept()
        connection = sock.makefile()
        print('Connection address:', address)
        for line in connection:
            print(line)
            if line == b'send_A1':
                # 
                # BUG `radiation` is undefined here.  Needs OOP to solve this.
                # 
                connection.write(
                    'A1={0},\r\n'.format(radiation).encode('utf-8')
                )
                connection.flush()
        sock.close()
        print('Verbindung vom Remote beendet.')


def main():
    thread = Thread(target=read_geiger_counter)
    thread.daemon = True
    thread.start()
    serve_radiation_values()


if __name__ == '__main__':
    main()
Antworten