Programm läuft nach Thread aufruf nicht weiter

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
audacity363
User
Beiträge: 83
Registriert: Dienstag 6. August 2013, 18:59

Guten Abend
Also ich müsste ein Ping ausführen der beim Ersten Start überprüft ob der Server da ist oder nicht. Wenn der Server nicht da ist soll der Ping immer weiter ausgeführt bis er da ist.
Das ganze sieht so aus:
Ping:

Code: Alles auswählen

def Ping():
    while True:
        serverHost = '192.168.178.43'
        serverPort = 7
        
        message = [b'ping']
        input = ""
        try:
            sockobj = socket(AF_INET, SOCK_STREAM)
            sockobj.connect((serverHost, serverPort))
            for line in message:
                sockobj.send(line)
                data = sockobj.recv(1024)
                input = data.decode("utf-8")
                sockobj.close()
                if(input == "true"):
                    Arduino_status = 1
                else:
                    Arduino_status = 0
        except ConnectionRefusedError:
            Arduino_status = 0
        finally:
            sockobj.close()
            print(Arduino_status)
            time.sleep(5)
Aufruf:

Code: Alles auswählen

print("Connecting to Arduino")
_thread.start_new_thread(Ping(), (1,))
time.sleep(3) #Zeit für den Ping
while(Arduino_status == 0):
    print("FEHLER: Arduino nicht erreicht")
    time.sleep(2)
print("[OK] Verbindung zum Arduino aufgebaut")
egal wie ich es drehe und wende. Nach dem _thread.start_new_thread(Ping(), (1,)) läuft das Main Programm nicht weiter.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das liegt daran, dass du gar keinen Thread startest. Vor dem Aufruf von ``start_new_thread`` führst du bereits ``Ping`` aus und übergibst es nicht als Funktion. Allerdings solltest du das _thread-Modul gar nicht verwenden, darauf deutet der führende Unterstrich hin. Verwende besser das threading-Modul.

Ein Blick in PEP 8 solltest du auch mal riskieren. serverPort sollte zum Beispiel besser server_port heißen, Variablen müssen nicht unnötig initialisiert werden, du solltest True/False verwenden und nicht 0/1 und die Bedingungen bei if und while gehören auch nicht in Klammern.
Das Leben ist wie ein Tennisball.
BlackJack

@audacity363: Warum ist `message` eine Liste? Das macht das Programm nur unnötig komplizierter.

Auch wenn es recht unwahrscheinlich ist, dass es bei jeweils vier Bytes in jede Richtung Probleme gibt: Das ist nicht sauber und robust `send()` und `recv()` so zu verwenden als wenn alle Daten in einem Aufruf gesendet oder empfangen wurden. Diese Garantie gibt die API einfach nicht her.

Das Dekodieren von vier Bytes die ausschliesslich aus ASCII-Werten bestehen, ist vielleicht auch etwas übertrieben.

Wenn statt 0 und 1 Wahrheitswerte verwendet werden, dann lässt sich die Zuweisung an die Statusvariable ohne ``if``/``else`` erledigen, denn die Bedingung selbst ist ja schon ein Ausdruck der `True` oder `False` als Ergebnis hat.

Es gibt noch einen Fehler, den Du uns verschwiegen hast, nämlich den `NameError` wegen `Arduino_status` beim Aufrufer. Das ist ein lokaler Name in `Ping()` auf den kann man ausserhalb von der Funktion nicht zugreifen.
audacity363
User
Beiträge: 83
Registriert: Dienstag 6. August 2013, 18:59

Mhh okey das ist heftig.
@EyDu
Okey ich habs jetzt umgeschrieben. Das mit den Klammern mach ich irgendwie aus Reflex da ich eigentlich in Java/C schreibe. Aber Java ist ein wenig inperfomant für den RaspberryPI. Wegen der Variablen Benennung: Das ist mir im Moment eher egal da ich im Moment eher rumteste und nachher die einzelnen Stücke zu einem Kompletten Programm zusammen setze. Also schreibe ich das ehh neu.

@BlackJack
Warum message ne Liste ist? Kp ich beziehe mein Wissen und daher auch die Codeschnipsel aus diesem Buch: http://www.amazon.de/Programming-Python ... 0596158106 . Dort wird gesagt das die Sachen per Byte übergesendet werden müssen. Auch wird dort für so einen einfach Client/Server keine andere Lösung genant. Ist es vielleicht veraltet? Habe es von meinem Vater. Die Variable Arduino_status ist oben im Programm deklariert, also sollte doch alle darauf zugreifen können (oder bin ich jetzt schon wieder zu weit in Java gerutscht?)?
BlackJack

@audacity363: Der Reflex mit den Klammern wäre auch in C falsch, denn auch dort hat ``function(callback())`` und ``function(callback)`` eine Unterschiedliche Bedeutung. Wobei die sich mit der Bedeutung in Python decken, im ersten Fall wird `callback` aufgerufen und der Rückgabewert an `function` übergeben, und im zweiten Fall wird die Funktion `callback` als Wert an die Funktion `function` übergeben. In Java sind Methoden keine Werte, da behilft man sich mit Exemplaren von Klassen die (nur) eine Methode haben, die über ein Interface festgelegt ist. In der Praxis sieht das dann so aus (ungetestet)

Code: Alles auswählen

function(new ICallback() {
    void callback(int value) { /* ... */ }
});
Wenn Du später ein Programm aus einzelnen Schnippseln zusammensetzt schreibst Du es ja eben *nicht* neu‽ Man sollte sich vernünftige und den Konventionen entsprechende Namen eigentlich grundsätzlich angewöhnen. Denn dieses „später” in „das mache ich später” kommt oft genug nie. Bis man dann selbst nach einem Jahr eigenen Quelltext liest und ihn nicht mehr versteht, oder der für erfahrene Programmierer komisch aussieht. Ich kann mich ja noch an `mixedCase`-Namen beim Lesen gewöhnen, aber alles was mit einem Grossbuchstaben anfängt ist in meinem Kopf ein Klassenname. Das kenne ich so aus Python und auch aus Java und finde es extrem verwirrend wenn jemand anfängt Funktionen so zu benennen. Das machst Du doch in Java (hoffentlich) auch nicht.

`message` ist eine Liste weil Daten als Bytes gesendet werden müssen ist eine komplett unsinnige Aussage. Das erklärt warum man ein `bytes`-Objekt verwendet, aber nicht warum *das* als einziges Element in einer Liste stecken muss. Vor dem versenden holt Du das ja auch aus der Liste heraus.

In Python wird (fast) nichts deklariert. Und wenn Du mit „oben im Programm” meinst, dass auf Modulebene der Name `Arduino_status` definiert ist, dann können da nicht alle drauf zugreifen. Nämlich die Funktionen nicht, die einen gleichlautenden lokalen Namen besitzen. Das ist in Java und C auch nicht anders, also kannst Du nicht zu weit in Java gerutscht sein.

Code: Alles auswählen

    int answer = 42;

    void foo(int value) {
        int answer = value;  // Hat keinen Einfluss auf `answer` ausserhalb der Funktion.
    }
Wenn man in Python irgendwo in einer Funktion/Methode etwas an einen Namen bindet, ist das für die ganze Funktion ein lokaler Name.

Wenn Du den Status nach aussen geben möchtest, läuft das auf eine Klasse hinaus. Und man sollte dann den Zugriff auf das Flag vielleicht auch gegen gleichzeitigen Zugriff und Verändern schützen, beziehungsweise gleich einen entsprechenden Typ aus dem `threading`-Modul verwenden.

Wobei diese Konstruktion sowieso nicht wirklich für den Einsatzzweck aus dem Aufruf-Beispiel passt. Da hätte man vorher auch einfach nur „pingen” können bis das erfolgreich war ohne das man einen eigenen Thread dafür starten muss. Die ganze Komplexität die sich daraus ergibt, bringt keinen Mehrwert.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

BlackJack hat geschrieben:In Java sind Methoden keine Werte, da behilft man sich mit Exemplaren von Klassen die (nur) eine Methode haben, die über ein Interface festgelegt ist. In der Praxis sieht das dann so aus (ungetestet)

Code: Alles auswählen

function(new ICallback() {
    void callback(int value) { /* ... */ }
});
Da fehlt aber ein `implements` oder `extends`, sonst erkennt Java den Typ der anonymen Klasse nicht. ;)
BlackJack

@snafu: Und wo sollte ich das schreiben? Der Typ ist doch `ICallback`. Die Klasse selbst hat keinen Namen. Darum heissen die ja auch *anonyme Klassen*.
Antworten