Fehlgeschlagene If-Abfrage

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
montus_pythonia
User
Beiträge: 10
Registriert: Donnerstag 27. August 2015, 18:51

Hallo liebe Leute dieses Python-Forums,
ersteinmal entschuldigt etwaige Fehler bei irgendwelchen Formatierungs- oder Einordungsfehlern meiner Inhalte hier - das ist mein erstes eigenes "Thema" ;D
Jetzt zu meinem Problem:
Ich programmiere auf einem Raspberry Pi und möchte einen TCP-Server erstellen der später dann Befehle von einer Android-App erhält und diese entsprechend verarbeitet. Das hat trotz meiner geringen Python-kenntnisse schon ganz gut geklappt (sonst entwickle ich in anderen Sprachen, jetzt soll auch Python dazu kommen daher auch die Anmeldung bei diesem Forum ;)). Der TCP-Server erhält bereits Nachrichten und sendet sie zur Kontrolle wieder zurück. Getestet habe ich das bisher mit dem Tool "Socket Test".
Nun soll er allerdings diesen erhaltenen String nicht nur "printen" sondern auch verarbeiten, dazu habe ich eine If-Abfrgage erstellt. Auch wenn "data" ganz offensichtlich "test" entspricht wird der Inhalt der If-Abfrgage jedoch nicht ausgeführt. Ist das ein Fehler beim en- bzw. decoden? Wie kann ich diesen beheben?
Habe bereits aufgrund eines anderen Fehlers die ersten zwei Zeilen hinzugefügt (Anleitung hatte ich von einem Link der mir vom Pi ausgespuckt wurde), dass hat ersteinmal auch geklappt. Liegt es an denen?

Hier erstmal der Code:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket
import sys

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_address = ('192.168.178.41', 21345)
print >>sys.stderr, 'server startet auf %s port %s' % server_address
sock.bind(server_address)

sock.listen(1)

while True:
        # Auf Verbindung warten
        print >>sys.stderr, 'Auf Verbindung warten...'
        connection, client_address = sock.accept()


        try:

                print >>sys.stderr, 'Verbindung mit', client_address, 'hergestellt'

                # Dateien empfangen und zurückschicken
                while True:
                        data = connection.recv(16)
                        print >>sys.stderr, 'Daten empfangen:', data

                        if data:
                                print >>sys.stderr, 'Daten zurückgeschickt'
                                connection.sendall(data)
                                if data is "test":
                                        print >>sys.stderr, 'Inhalt ist Test!'
                                else:
                                        print"Kein Befehl erhalten"
                        else:
                                print >>sys.stderr, 'Verbindung mit', client_address, 'beendet'
                                break
Ich hoffe ihr könnt mir bei diesem Problem helfen - aber da bin ich mir sicher, scheint ja ein fleißiges Forum hier zu sein :wink:
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@montus_pythonia: Erst einmal willkommen im Forum!
Der Operator 'is' prüft auf Objekt-Identität, und dies ist in Deinem Fall nicht gegeben.
Richtig wäre

Code: Alles auswählen

if data == 'test':
BlackJack

Wobei es selbst bei ``==`` nicht robust ist weil TCP ein Datenstrom ist und ``recv(16)`` zwischen 1 und 16 Bytes aus diesem Datenstrom liefern kann und welche das hängt nicht davon ab was zusammen auf der Gegenseite gesendet wurde. Also im Extremfall müsste das Programm auch damit klarkommen wenn das 'test' in vier Aufrufen als einzelne Bytes gelesen wird.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

BlackJack hat geschrieben:Wobei es selbst bei ``==`` nicht robust ist weil TCP ein Datenstrom ist ...
Ja, das stimmt. Dann müssten wir aber auch über Protokolle sprechen: fixe Längen oder Terminatoren oder ob die Sendestelle garantiert den write-channel des Sockets schließt (was hier angenommen wird). Ich wollte die Antwort nicht direkt überfrachten, da die Wahrscheinlichkeit hoch ist, dass die wenigen Daten in einem Rutsch durchkommen. Aber der Hinweis auf mangelnde Robustheit ist sicherlich angebracht.
montus_pythonia
User
Beiträge: 10
Registriert: Donnerstag 27. August 2015, 18:51

Erstmal vielen Dank für die schnellen Antworten,
ich habe jetzt das "is" gegen ein "==" ausgetauscht, jedoch leider immernoch nicht das gewünschte Ergebnis erhalten.
Was ich mir allerdings immernoch nicht erklären kann ist, warum die Variable data nachdem sie "geprinted" wurde Augenscheinlich identisch mit dem vorher von mir eingegebenen Text ist und dennoch nicht richtig "erkannt" wird.
BlackJack

@montus_pythonia: Wahrscheinlich weil sie nicht identisch ist. Kann es zum Beispiel sein dass Du ein Zeilenendezeichen sendest und das augenscheinlich übersiehst?
montus_pythonia
User
Beiträge: 10
Registriert: Donnerstag 27. August 2015, 18:51

Ja, in die Richtung ging ja meine erste Vermutung (ob es evtl. etwas mit dem codieren zutun hat, ich hatte mal ein ähnliches Problem mit vb.net). Kann man soetwas quasi "sichtbar machen"? Ich weiß ehrlich gesagt nicht genau wo ich ansetzten soll, aber wenn dieses Zeilenendzeichen bekannt ist kann man es ja kompensieren.
BlackJack

@montus_pythonia: Lass Dir von den empfangenen Daten mal das Ergebnis der `repr()`-Funktion anzeigen.
montus_pythonia
User
Beiträge: 10
Registriert: Donnerstag 27. August 2015, 18:51

Wollte ich gerade eigentlich direkt mal ausprobieren, aber ich habe festgestellt dass ich jetzt (scheinbar durch diese Änderung)vor einem neuen Problem stehe: (ich merke schon in Python muss ich noch viel lernen ;))
Es kommt nur folgende Antwort:
" File "server.py", line 33

^
IndentationError: unexpected unindent"

Ich hatte das Problem bisher trotz zahlreicher Änderungen am Code noch nie und habe gelesen dass das mit falschen Leerzeichen/Tabulatoren zutun hat?
Habe meinen Code bereits in Word kopiert und auch anstelle der Tabulatoren jeweils vier Leerstellen getestet, mir ist jedoch keine unregelmäßigkeit aufgefallen, trotzdem geht es nicht.
Der Fehler oben kommt überings aus einem zweiten gerade erstellten Projekt wo ich die Abfrage nach data == "test" erstmal weggelassen habe, Zeile 33 ist in diesem Fall die allerletzte leere Zeile (was mich noch mehr wundert). Ich hoffe das sprengt hier jetzt nicht diesen Beitrag und ihr könnt mir auch hier weiterhelfen!
BlackJack

@montus_pythonia: Ohne den Quelltext kann man da nicht viel zu sagen ausser das es anscheinend einen Fehler in der Einrückung gibt.

Was Quelltext in Word kopieren bringen soll ist mir nicht so ganz klar. Ich hoffe Du hast nicht auch den umgekehrten Weg gemacht, denn dann können komische Sachen passieren wenn die Textverarbeitung automatisch Veränderungen beim Einfügen vorgenommen hat. ”Smart punctuation” wäre da so ein Feature was Quelltexte gerne mal kaputt macht.

Einrücken mit vier Leerzeichen pro Ebene. Immer. Keine Tabs. Nie. Sonst gibt's früher oder später Probleme mit dem eigenen Code, oder wenn man welchen von woanders übernimmt, oder wenn andere Deinen Code ausprobieren sollen/wollen.
montus_pythonia
User
Beiträge: 10
Registriert: Donnerstag 27. August 2015, 18:51

Anhand des Einfügens in Word habe ich Fehler erkennen wollen mithilfe der sichtbar gemachten Formatierungszeichen. Von Word habe ich natürlich nicht kopiert. Ich werde aber jetzt nochmal den gesamten Code neu eintippen und besonders auf Leerschritte achten, melde mich dann ;)
BlackJack

@montus_pythonia: Whitespace sollte ein guter Texteditor eigentlich anzeigen können.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@montus_pythonia: Wie Blackjack mir gerade zuvor gekommen ist: ohne Quelltext lässt sich da wenig sagen. Aber Word solltest Du aussen vor lassen. Nimm statt dessen einen Texteditor Deiner Wahl, d.h. der, mit dem Du am besten zurecht kommst. Auf dem Mac würde ich Dir BBEdit empfehlen, andere nutzen gerne Sublime (Mac, Linux), aber frage drei Leute und Du bekommst vier Empfehlungen :)
Wichtig: keine Tabulatoren verwenden, sondern stets mit Leerzeichen einrücken. Ein guter Editor lässt sich so einstellen, dass auch bei Nutzung der Tabulatortaste die korrekte Zahl von (4) Leerzeichen eingefügt wird. Auch Sonderzeichen lassen sich sichtbar anzeigen, um so typische Python-Formatierfehler erkennen zu können - die mit ein wenig Erfahrung aber rapide abnehmen.
montus_pythonia
User
Beiträge: 10
Registriert: Donnerstag 27. August 2015, 18:51

Ok, ich habe das ganze schnell noch etwas umgetippt, das sieht jetzt so aus:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket
import sys

sock = socket.socket(socket.AF_INET,server.SOCK_STREAM)

server_address=('192.168.178.41', 21345)
print >>sys.stderr, 'Server startet auf %s port %s' % server_address
sock.bind(server.address)

sock.listen(1)

while True:
    #Auf Verbindung warten
    print >>sys.stderr, 'Auf Verbindung warten...'
    connection, client_address = sock.accept()

    try:
        print >>sys.stderr, 'Verbindung mit', client_address, 'hergestellt'
        #Daten empfangen und zurückschicken
        while true:
            print >>sys.stderr, 'Daten empfangen:', connection.recv(16)
            if data:
                print >>sys.stderr, 'Daten zurückgeschickt'
                connection.sendall(data)
                if connection.recv(16) == "Test":
                    print >>sys.stderr "Inhalt ist Test!"
            else:
                print >>sys.stderr, 'Verbindung mit', cient_address, 'beendet'
                break
Fehlermeldung hat sich auch verändert:
File "server.py", line 29
print >>sys.stderr "Inhalt ist Test!"
^
SyntaxError: invalid syntax
Das mit den anderen Editoren ist allerdings nicht so einfach, da ich (wie anfangs erwähnt) ja auf dem Raspberry Pi schreibe, ich weiß nicht ob da beim herumkopieren nicht auch Fehler entstehen können...
montus_pythonia
User
Beiträge: 10
Registriert: Donnerstag 27. August 2015, 18:51

Sorry war etwas zu schnell, diesen Fehler habe ich selbst entdeckt, aber es taucht wieder der Alte auf:
File "server.py", line 33

^
IndentationError: unexpected unindent
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@montus_pythonia: Dein Code kann so gar nicht funktionieren. In Zeile 25 verwendest Du 'data', was zuvor nicht definiert wurde. In Zeile 27 sendest Du den Inhalt von 'data', den es noch gar nicht gibt, sondern der in Zeile 28 zwecks Vergleich erst empfangen werden soll, aber bereits in Zeile 24 empfangen wurde. Weiter beginnst Du in Zeile 20 einen 'try' Block, der nicht mit einen except geschlossen wird. Welche Exception möchtest Du an dieser Stelle denn abfangen? Und in Zeile 29 hast Du ein Komma vergessen - was sich dann als Syntax Fehler bemerkbar machen dürfte.
Zuletzt geändert von kbr am Freitag 28. August 2015, 22:58, insgesamt 1-mal geändert.
BlackJack

@montus_pythonia: Zu dem ``try`` fehlt ein ``except`` und/oder ein ``finally``.
montus_pythonia
User
Beiträge: 10
Registriert: Donnerstag 27. August 2015, 18:51

Ok, vielen Dank nochmal, ich habe jetzt hier meinen Code mal "gesäubert" und "repariert", er sieht jetzt so aus:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket
import sys

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_address = ('192.168.178.41', 21345)
print >>sys.stderr, 'Server startet auf %s port %s' % server_address
sock.bind(server_address)

sock.listen(1)

while True:
    # Auf Verbindung warten
    print >>sys.stderr, 'Auf Verbindung warten'
    connection, client_address = sock.accept()

    try:
        print >>sys.stderr, 'Neue Verbindung mit:', client_address

        # Daten empfangen und zurückschicken
        while True:
            data = connection.recv(16)
            print >>sys.stderr, 'Daten empfangen:', data
            if data:
                print >>sys.stderr, 'Daten werden zurückgeschickt'
                connection.sendall(data)
                if connection.recv(16) == "test":
                    print >>sys.stderr, "Data ist test!"
                else:
                    print >>sys.stderr, "Data ist nicht test!"
            else:
                print >>sys.stderr,'Verbindung mit', client_address, 'beendet'
                break

    finally:
        # Verbindung schließen
        connection.close()

Das Problem ist und bleibt jetzt bei Zeile 30, egal was data ist wird die If-Abfrage nicht ausgeführt.
Wenn ich in Zeile 26 anstelle von data "connection.recv(16) einsetzte ändert sich an der Ausgabe überings nichts, außer dass ab und zu nur "Daten empfangen:" geprinted wird, nicht der Text der Nachricht dahinter. Dass ist jedoch rein zufällig und ich konnte kein Muster dahinter erkennen.
Ich hoffe ihr habt mehr Ideen ;)
BlackJack

@montus_pythonia: Das TCP ein Datenstrom ist und das so sowieso nicht robust funktionieren kann habe ich ja schon mal geschrieben. Was sendest Du denn jetzt? Das müssten ja 1 bis 16 Bytes irgendwas gefolgt von 'test' sein und dann mit der Hoffnung verbunden das der ``recv(16)``-Aufruf die ”irgendwas”-Bytes liest und der zweite dann das gesendete 'test'. Sehr unwahrscheinlich dass das klappt.

Nochmal: Benutze `repr()` um zu sehen was da *tatsächlich* ankommt.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@montus_pythonia: Ich habe Dir einen kleinen (ungetesteten) Beispielcode aufgesetzt, da Socket-Programmierung nicht ganz trivial ist. Da beide Funktionen mit 'connection' das selbe Socket-Ojekt nutzen, sind dies auch Aspiranten für Methoden einer gemeinsamen Klasse. Zudem auch das Socket-Objekt selbst noch erzeugt werden muss. Der Code ist nicht komplett und ersetzt auch keinen dauerhaft laufenden Prozess, aber vielleicht hilft er Dir weiter.

Code: Alles auswählen

from io import BytesIO

# do additional imports and set up socket and connection here ...

def receive_data(connection):
    """
    Return the data received from the given socket-object.
    """
    buffer = BytesIO()
    while True:
        data = connection.recv(1024)
        if data:
            buffer.write(data)
            continue
        data = buffer.getvalue()
        print >>sys.stderr, 'Data received:', repr(data)
        return data

def send_data(connection, data):
    """
    Send data by means of the given socket-object.
    """
    try:
        connection.sendall(data)
    except:
        # catch all, normally a bad idea
        print >>sys.stderr, 'Error sending data'
    else:
        print >>sys.stderr, 'Data have been sent back'
    finally:
        connection.close()
        
data = receive_data(connection)
send_data(connection, data)
Zuletzt geändert von kbr am Samstag 29. August 2015, 20:29, insgesamt 1-mal geändert.
Antworten