Socket Verbindung -Problem beim warten auf den Marker

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Black Panther
User
Beiträge: 27
Registriert: Samstag 11. Juni 2016, 19:09

Hallo liebe Community,

ich bin neu hier. Habe schon ein paar Wochen lang mich mit Python und den Tutorials rund herum beschäftigt. Ich habe ein konkretes Problem bei der Verbindung mit einem Socketadapter. Ich programmiere derzeit noch unter Windows mit der IDE Pycharm. Bin damit auch sehr zufrieden. Mein Programm läuft leider nicht richtig bei der Verwendung des Raspberry Pi. Es gibt ein Problem bei Datenerhalt.


Das Programm soll im Prinzip folgendes ausführen.
1. Barcode soll eingescannt werden oder per Hand ausgefüllt werden ( der Socketadapter bzw Server sind als Vorraussetzung da)#
2. Initialisierung der Verbindung (Socket und Port aus Ini lesen)
3. Barcode noch einmal Zwischenspeichern in einer Textdatei
4. mit dem Server verbinden
5. Zeichencode vereinbaren
6. einen Login beim Server ausführen
7. eine bestimmt Funktion nutzen und ein Array aus STringcodes an den Server schicken
8. warten auf Antwort


und genau jetzt kommt das Problem...... wenn ihr euch die Zeilen nähe betrachtet :

Code: Alles auswählen


#Ueberpruefung, ob das Ende erreicht ist und $ uebergeben wurde
Ende = '$'
total_receivedata_reg = []
data = ''
while True:
         data = str(s.recv(1024))                          #Daten werden empfangen
         if Ende in data:
             total_receivedata_reg.append(data[:data.find(Ende)])   #Suchalgorithmus fuer das Ende
             total_receivedata_reg.append(data)

             break
         total_receivedata_reg.append(data)

print total_receivedata_reg         
erhalte ich unter Nutzung eines PC's wo auch der SOcket drauf läuft folgendes als ANtwort vom Server:

"STring"," String "," String" , "STring", "$"


Beim Raspberry erhalte ich das nicht so schön:

"String",
"STring,String,String","$"

und das nervt mich derzeit. Ich versteh die Methode mit dem Endmarker einfach nicht richtig. Obwohl das perfekt für mich wäre, weil ich ja mitdem $ Zeichen ein perfektes Ende habe.
Kann mir jemand ein gutes Beispiel verraten oder eine Info Quelle geben?

LG

Black Panther
Zuletzt geändert von Anonymous am Samstag 11. Juni 2016, 20:36, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@Black Panther: Ich verstehe nicht so ganz was das zweite `append()` im ``if``-Zweig machen soll. Das hängt da ja am Ende noch mal alle Daten von dem Stück vom Datenstrom an in dem das Endzeichen enthalten ist. Das erscheint mir unsinnig.

Am Ende möchtest Du vielleicht noch die Einzelteile in `total_receivedata_reg` zu einer Zeichenkette zusammensetzen mit ``result = ''.join(total_receivedata_reg)``.
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@Black Panther: Wenn Du Daten hier angibst und fragst, warum die Daten mal so mal so aussehen, solltest Du schon sehr exakt sein, was Du erhältst. Ich glaube kaum, dass Windows andere T großschreibt als der Raspberry. Auch die Verteilung von Leerzeichen, Kommas und Anführungszeichen ist seltsam.

Bitte beschreibe mal exakt, wie das Datenformat aussieht, wie sieht die Sende-Seite aus, wie die Empfangsseite. Was möchtest Du am Ende erhalten?

Der str-Aufruf auch s.recv ist überflüssig, weil recv schon einen Bytestring liefert. In welchen Blöcken recv die Daten liefert ist aber nicht festgelegt. Wenn Du also erwartest, dass Du zum Schluß schon eine schön aufgeteile Liste erhältst, muß ich Dich enttäuschen. Den Verarbeitungsschritt mußt Du selbst programmieren, nachdem Du die Teilstücke aus total_receivedata_reg zu einem String per join zusammengefügt hast.

Hier mal ein Generator, der es erlaubt, auch mehrere Nachrichten hintereinander zu schicken:

Code: Alles auswählen

def recv_blocks(socket, end_of_block='$'):
    total = ''
    while True:
        data = socket.recv(1024)
        if not data:
            if total:
                raise ValueError("Partial Block", total)
            return
        parts = data.split(end_of_block)
        total += parts[0]
        if len(parts) > 1:
            # end_of_block found
            yield total
            for total in parts[1:-1]:
                yield total
            total = parts[-1]


blocks = recv_blocks(s)
print next(blocks)
Black Panther
User
Beiträge: 27
Registriert: Samstag 11. Juni 2016, 19:09

Hallo,

vielen Dank für die Antworten bisher.

@BlackJack: mir war das zweite append auch nicht so ganz klar. Gerade als Anfänger versuche ich auch mich an Beispielen zu orientieren. Im Fall des Socketadapters habe ich mich auf folgende Quelle berufen:

http://code.activestate.com/recipes/408 ... o-recvall/

Anhand dieser Anleitung habe ich mir das Abteil mit dem Marker rausgesucht, weil es meinen Ansprüchen sehr nahe kommt. In erster Linie programmiere ich aber dafür, dass mein Raspberry mit dem Python Script läuft und erfolgreich kommuniziert. Und das ist ja wie gesagt nicht der Fall.

@Sirius3: Im nachhinein betrachtet, habe ich die SItuation und die Ausführung vielleicht etwas falsch dargestellt. Auch die die Ausgabe "STring" und "String" war im Endeffekt nur ein Beispiel. Ich versuche noch einmal nachstehend den Sachverhalt aufzuarbeiten.


Ich melde mich über folgende Daten über den Socketadapter beim Server an. Es ist eine Verkettung von Strings. Mit meiner Laienhaften Einschätzung und mit der Unterstützung von Print sollte diese Angaben auch ordentlich übermittelt werden.

Code: Alles auswählen

reg_login = ("regLogin,"+"stationNumber,"+"stationPassword,"+"user,"+"password,"+"client,"+"registrationType,"+
        "systemIdentifier"+station_number+",,,,01,S,"+"TestUser$")
print reg_login
s.send(reg_login)
Teilweise sind die Strings Vorgaben oder werden durch EInlesungen von mir selber eingefügt. Die Ausgabe vom Server sollte in ähnlicher Art und Weise ablaufen. Im Prinzip möchte ich ein Array haben. Ich kann die Angaben jetzt nicht genau abbilden, da mir das System fehlt, aber so in der Art sollte es ablaufen:

"0","locale","pers_ID" ...usw. bis "$"

Dieses in Möglichkeit vollabefangene Array bis zum "$" möchte ich gerne auswerten. Einzelne Strings in Variablen speichern. Das funktionierte auch alles auf dem WIn PC. Beim Raspberry sehen die Antworten so aus:

"0",
"locale,pers_ID,de usw.",
"$"

Hoffe ich konnte das Problem einigermaßen darstellen. Vereinbarter Zeichensatz mit Server war übrigens ausprobiert mit UTF-8 und windows 1252.


LG

Black Panther
BlackJack

@Black Panther: Muss es gerade dieser Marker sein? Geht eventuell auch ein Zeilenende? Denn dann könnte man sich von dem Socket einfach ein Dateiobjekt geben lassen und von dem ganz einfach mit `next()` die nächste Zeile abfragen. Ansonsten könnte man sich mit den Klassen aus dem `io`-Modul vielleicht auch einen Reader mit einem eigenen Marker für ein ”Zeilenende” basteln.


Das Senden hast Du nicht robust gemacht, da musst Du `sendall()` statt `send()` verwenden. Sonst ist nicht garantiert, dass alle Daten gesendet wurden.

Dieses zusammenstückeln mit ``+`` ist schwer lesbar. Gerade wo man das hier ohne Syntaxhervorhebung sieht ist nicht leicht nachvollziebar was nun eigentlich Zeichenkette und was Variable ist. Welche Kommas in den Daten und welche im Programm stehen. Es gibt die `format()`-Methode auf Zeichenketten um das lesbarer hinzubekommen.

Du *musst* beim Empfänger alle Daten zu einer Zeichenkette zusammenfassen und dann entsprechend Deinen Kriterien in eine Liste mit den Einzelteilen zerlegen. Und das musst Du auch auf dem PC machen, auch wenn Du denkst das sei nicht nötig und liegt irgendwie nur am Raspi. TCP ist ein Datenstrom und bei einem `recv(n)`-Aufruf bekommst Du 1 bis n Bytes aus diesem Datenstrom. Wieviele das sind solltest Du als Zufall ansehen, denn da gibt es keine garantien. Dein Programm müsste im Extremfall auch damit klar kommen wenn jeder `recv()`-Aufruf ein einzelnes Byte aus dem Datenstrom liefert.

Statt selber ein Format zu erfinden, würde ich ja nach Möglichkeit etwas vorhandenes verwenden. Zum Beispiel JSON. Das macht das erstellen und parsen der Nachrichten deutlich einfacher.

Und statt roher Sockets wäre eventuell auch ein existierendes Protokoll eine überlegung Wert.
Black Panther
User
Beiträge: 27
Registriert: Samstag 11. Juni 2016, 19:09

@BlackJack...vielen Dank für die Tipps. Der Reihe nach möchte ich dir aufschlüsseln, was bei mir angekommen ist:

1. DIe Verbesserung mit dem sendall() ist sehr gut, da es bisher immer geklappt hat, habe ich nach keinen Verbesserungen gesucht.
2. Die Lesbarkeit des übergebenden Arrays ist wirklich nicht gut. In der IDE sieht man das konfortabel und da dieser Punkt nicht das Problem ist, schieb ich es erstmal auf die Darstellung im Forum.
3. Der Empfang des Markers wäre wie gesagt günstig. Wie ich verstanden habe, möchtest du mir jedoch eine andere Methode ans Herz legen. Ich könnte mir da im Prinzip nur vorstellen, das ich auf alle Zeichen warte und dann wieder ne Stückelung aufgrund des Kommas vornehme und dieses Array behandle.
4. Die Methode z.B JSON ist mir nur durchs lesen bekannt. Generell habe ich große Problem mit nicht in Python installierte Module. Mein Umgang mit PyUSB hat mich schon einmal in die Schranken gewiesen.
5. Diese Sachemit der Protokoll-Überlegung klingt auch interessant. Ich brauch bitte unbedingt noch einen Anstoß wie "die generelle Thematik heißt"nach der ich Suche. Beziehungsweise wären konkrete Tutorials nicht schlecht.

Insgesamt gesehen sehe ich Vorwärtsbewegungen bei Python, aber mein Wissen reicht noch nicht für unabhängige Datenstrombehandlung aus.

LG

Black
BlackJack

@Black Panther: Ad 2. Man kann die Darstellung im Forum mit Codebox-Tags statt Code-Tags deutlich verbessern. :-)

Ad 3: Ich frage ob *dieser* Marker sein muss, also '$'. Denn wenn innerhalb der Nachrichten kein Zeilenendezeichen vorkommt, kann man sich sehr viel von der Programmierarbeit sparen und sich vom `socket`-Objekt ein Dateiobjekt geben lassen, wo man dann einfach *Zeilen* lesen kann. Das hier würde alle Zeilen, die über die Verbindung kommen, in einer Schleife verarbeiten/ausgeben:

Code: Alles auswählen

# ...
      lines = sock.makefile()
      for line in lines:
            print line
Ad 4. Für JSON gibt es ein Modul in der Standardbibliothek. Da würde man sich vom Socket ebenfalls ein Dateiobjekt geben lassen und kann dann darauf die entsprechenden `load()`- und `dump()`-Funktionen aufrufen.

Ad 5. RPC ist da wohl das Stichwort. XML-RPC, JSON-RPC, oder auch eine Web-API über HTTP und JSON. Wobei es da auch darauf ankommt was denn über diese Verbindung überhaupt geregelt werden soll.
Black Panther
User
Beiträge: 27
Registriert: Samstag 11. Juni 2016, 19:09

@BlackJack....Danke schön....werde das dementsprechend morgen testen.

Ich habe kurz etwas zu makefile nachgelesen. Die Art und Weise finde ich gut, jedoch fehlt mir etwas Kontext. Es wird also ein Datenobjekt erzeugt das in einem gewissen Blocking mode läuft. Das heißt für Echtzeitprogrammierung vielleicht nicht ganz so gut (ist aber nicht meine Anforderung). Ist das makefile Objekt nur physisch kurz in der Schleife vorhanden oder wird das richtig abgelegt irgendwo?

Sind meine Annahmen richtig:?
1. makefile abwarten und über Schleife in eine Variable (Array speichern)
2. Array mit split() nach Kommas filtern
3. mit Replace die Leerzeichen rausschmeisen
4. Ausgabe...eventuell manche Strings in Varaiblen returnen

LG


Blacky
BlackJack

@Black Panther: `recv()` ist doch auch blockierend solange das Socket kein Timeout gesetzt hat. Du willst doch, zumindest im bisher gezeigten Code, blockierend lesen bis eine komplette Nachricht zusammengekommen ist.

Das Dateiobjekt ist in meinem Beispiel ja offensichtlich an den Namen `lines` gebunden. Es gelten die üblichen Regeln: Das Objekt existiert mindestens solange wie es irgendwie vom Programm über einen Namen oder in einer Datenstruktur erreichbar ist. Man kann es natürlich auch hinter ``in`` erzeugen und nicht an einen Namen binden. Für den Fall das man das nach der Schleife nicht mehr braucht. Ich weiss ja nicht mal ob die Schleife überhaupt gebraucht wird. Ich habe nämlich immer noch nicht so recht verstanden was das für Daten sind die Du da empfängst, und ich weiss auch nicht ob Du jetzt davon ausgehst, dass das Zeilenendezeichen das Ende eines Datensatzes markiert. Also braucht man die Schleife nicht für das was Du in Deine `recv()`-Schleife machst. Denn da braucht man dann ja nur eine Zeile, und die kann man mit `next()` von dem Objekt abfragen. Dann muss man aber das Dateiobjekt an einen Namen binden, sonst kann man ja nur einen Datensatz lesen.

Bei den Punkten: Das was Du hier immer Arrays nennst, sind Listen. Es gibt auch Arrays, das ist was anderes. Welche Leerzeichen? Sollte man die denn überhaupt senden wenn man sie hinterher wieder rauswerfen muss? Und nochmal die Sache mit dem Format: Wenn man sich so etwas selber bastelt, hat man Einschränkungen die vorhandene Formate nicht haben. Beispielsweise darf in den Daten bei Dir nirgends ein Komma vorkommen wenn Du einfach `split()` zum aufteilen verwendest.

Wieviele Datensätze kommen denn da insgesamt von der Gegenseite über diese Verbindung? Sag jetzt bitte nicht, nur einer, denn dann könnte man sich das alles viel einfacher machen. :-)
Black Panther
User
Beiträge: 27
Registriert: Samstag 11. Juni 2016, 19:09

Stimmt.....du hast Recht, es sind Listen. Bei der Funktion der Anmeldung ( Reglogin) wird im Prinzip nur ein Datensatz gebraucht. Der beginnt meistens mit der dem ersten String ("0") und endet mit dem "$" als Abschlusszeichen. Danach rufe ich immer wieder Funkionen des Servers auf, die ich anspreche und Infos erwarte. Zur Nutzung der Funktion muss ich einige Variablen aus dem reglogin wiederverwenden ("locale", "perID" usw.).

Insgesamt ist es das Problem eines Anfängers, nie abschätzen zu können, ob man etwas richtig macht.

Wie sehe die ANtwort von dir aus, wenn ich sage : "Ich benötige nur einen Datensatz"


LG

Blacky
BlackJack

@Black Panther: Na wenn nur ein Datensatz in die Richtung über die Verbindung geht, dann braucht man kein Endekennzeichnen, dann kann man als Ende einfach die Verbindung schliessen.
Black Panther
User
Beiträge: 27
Registriert: Samstag 11. Juni 2016, 19:09

@BlackJack ....mittlerweile habe ich das Problem mit der Datenverbindung gelöst und stolpere in die nächsten kleinen Baustellen....

Status: Mittlerweile benutze ich den Raspberry in Kombination mit einem 16x2 Zeilen Display mit Hintergrundbeleuchtung.

Probleme habe ich derzeit beim logging, try and exception und Status einer LED (Backlight) belassen bis er abgelöst wird? Nachstehend will ich die Probleme näher benennen:

1. Beim logging kommt bei mir eine Gewisse Unsicherheit durch. Derzeit baue ich mein Format folgender Maßen auf:

Code: Alles auswählen

# festlegen des Logging Basic Level
logging.basicConfig(level=logging.INFO)  # hier wurde das Info Level ausgewaehlt
logger = logging.getLogger("Mitschnitt")  # Name der Aufzeichnung
logger.setLevel(logging.INFO)
handler = logging.FileHandler("hello.log")  # Logdatei Name
handler.setLevel(logging.INFO)

# festlegen der Formatierung zur Uebergabe
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
Für Testzwecke sollen alle Aufzeichnung, ab dem Level Info und Priorität darüber aufgenommen werden. Später nur noch ab Level Error. Wie setzt man das Professionell um?

2. Try and Exception: Wenn man die Fehler nicht unbedingt kennt ist es schwer einen Abfang zu realisieren. Bei der Socketverbindung habe ich nur einen einfach ABfang gemacht.

Bsp:

Code: Alles auswählen

# Verbindungsaufbau, Daten werden aus Ini Datei geholt, Filterung nach Vorgaben
def verbindungsaufbau():
    try:
        info = open("//FUJI-SERVER2/temp/python.ini", "r")
        erhalt_init = info.readlines()
        host = ""
        port = ""
        for temp in erhalt_init:  # Schleife zum durchsuchen der Ini-Datei
            if "Host" in temp:  # jeweiliger Ablauf zum Filtern der Ini-Datei an Hand von Suchbegriffen
                host = temp
                host = host.split("=")
                host = str(host[1])
                host = host.rstrip()
            if "Port" in temp:
                port = temp
                port = port.split("=")
                port = str(port[1])
                port = int(port.replace("\n", ""))
        addr = (host, port)  # Variable zum zusammenfassen der Verbindung
        s.connect(addr)  # connect zum Socketadapter
    except socket.error:
        print("Verbindung zur Datenbank ist nicht moeglich")
3. Die letzte Rubrik beschäftigt sich mit dem 16x2 LC-Display mit I2C Ansteuerung. Die Integration und die Ansteuerung ist mir gelungen. Lediglich am Python Code scheitert es bei mir. Ich möchte das Zustände wie grüne Beleuchtung erhalten bleiben, solange bis Sie vom nächsten abgelöst werden.

Code: Alles auswählen

 #fuer Raspberry Anwendung (Displaysteuerung)
import time
import Adafruit_CharLCD as LCD
# Verfuegbarkeit der I2C Schnittstelle und LC-Display
lcd = LCD.Adafruit_CharLCDPlate()


def lcd_ini():
    lcd.clear()
    lcd.set_color(0.0, 0.0, 0.0)
an manchen Stellen nutze ich dann die Beleuchtungen, aber SIe werden nur kurz gehalten.

Code: Alles auswählen

def zeichensatzvereinbarung():  # Zeichensatzvereinbarung nach europaeischen Standard
    s.sendall("windows-1252$")
    print s.recv(1024)
    lcd_ini()
    lcd.set_color(0.0, 1.0, 0.0)
    lcd.message("Anmeldung\n erfolgreich")
    '''
Mehr oder weniger ist es das....womit ich mich rumschlage. Wenn du wirklich viel Zeit hättest, Black Jack würde ich teilweise gern meinen kompletten Code (keine ANgst nur rund 200 Zeilen) überprüfen lassen. ich glaube, da gibt es Optimierungspotenzial....nur leider finde ich als Anfänger nicht die ANsätze.
Zuletzt geändert von Anonymous am Freitag 1. Juli 2016, 14:55, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@Black Panther: Ad 1. Warum setzt Du das Level beim Handler und warum machst Du das alles so umständlich statt `basicConfig()` für all das zu verwenden?

Code: Alles auswählen

logging.basicConfig(
      filename='hello.log',
      format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
      level=logging.INFO,
)
Und später im Code kann man sich dann den Root-Logger holen und da das gewünschte Level ändern. Zum Beispiel aus einer Konfigurationsdatei oder als Argument von der Kommandozeile. Oder über `dictConfig()` oder `fileConfig()` aus `logging.config`, womit man viel weitreichender alles mögliche rund ums Logging Konfigurieren kann.

Ad 2. Da fehlt irgendwie eine Frage‽ Die Ausnahmebehandlung ist Mist, zum Teil aber auch weil die ”Funktion” keine saubere Funktion ist. Wo kommt das `s` her? Werte ausser Konstanten, die in einer Funktion oder Methode verwendet werden, sollten als Argumente übergeben werden. Ergebnisse als Rückgabewerte die Funktion verlassen. Und wenn innerhalb der Funktion eine Ausnahmesituation entsteht die nicht sinnvoll innerhalb der Funktion behandelt werden kann, dann sollte die Funktion das dem Aufrufer über eine Ausnahme mitteilen. Das ``try``/``except`` gehört an dieser Stelle also nicht in dieser Funktion, sondern dort hin wo die Funktion aufgerufen wird. Sonst bekommt man dort ja nicht mit wenn der Verbindungsaufbau nicht funktioniert hat.

Die Datei wird geöffnet aber nicht geschlossen. Hier bietet sich die ``with``-Anweisung an.

Die Namen vor der Schleife an sinnlose Platzhalterwerte zu binden macht nicht viel Sinn. Wenn dann sollte man sie an `None` binden und nach der Schleife prüfen ob beide Werte dann einen anderen Wert haben. Allerdings würde ich hier sowieso nicht irgendein Dateiformat erfinden. Es gibt INI-Dateien, oder JSON, und für beides Module in der Standardbibliothek. Da muss man nichts neues erfinden.

Ad 3. Was heisst die Beleuchtungen werden nur kurz gehalten?
Black Panther
User
Beiträge: 27
Registriert: Samstag 11. Juni 2016, 19:09

@ BlackJack : Vielen Dank für deine Antwort.
Ad1: Im nachhinein betrachtet hast du Recht, das war etwas to much. Deine Varainte pflegt sich etwas leichter ein. Im Prinzip lege ich somit die Basis Config fest (steckt ja schon im Namen)....und kann dann in den einzelnen Funktionen die Log Level ändern und somit Error, Warning und all die anderen Möglichkeiten setzten. Kann ich die allgemeinen Aufzeichnungen dann irgendwann nur auf Error begrenzen. Ansonsten könnte ja sehr viele Daten mit Info anfallen, die ja nicht wirklich gebraucht werden, oder?

Ad 2: Die Dateiöffnung hat ich mehrere Male vorgenommen, leider nur in ein von den 3 Fällen geschlossen, somit konnte ich das auch nachpflegen. Bei der Übergabe von Argumenten bin ich leider noch nicht so ganz sicher. Rückgabewerte hatte ich später verwendet, das funktioniert mittlerweile auch. "Try" and "Except" stellt sich für mich als sehr schwierig heraus. Es wird immer geraten nichts zu pauschalisieren, also dem Code im generellen abfangen. Die einzelnen Fehler kann man aber nur durch "Feldversuche" ermitteln, sonst kann ich für mich erstmal nur "Abbruch zur Datenbank" und "Abbruch Dateiöffnung" beispielsweise festlegen.

Ad 3: Beleuchtung hat sich erledigt. Ich hatte das 16x2 DIsplay mit einer Bibliothek von Adafruit betrieben. Leider war mir nicht im klaren, das die Adressierung etwas wechselte. So ließen sich die Werte mit bestimmten Aufrufen (1.0, 0.0, 1.0) erzeugen. Bei mir wichen die Werte ab vom Original, also hab ich einfach mal getestet, wann was eintritt. Das Kapitel ist jetzt auch geschlossen.


Damit du nicht immer nur ein Teil meiner Programmierung siehst, schicke ich dir den Code mal per PN. Logging und Try and Except muss ich natürlich später noch nacharbeiten. Manchmal fehlt mir gegenüber dir auch das nötige Hintergrundwissen.
BlackJack

@Black Panther: Ad 1: In der Python-Dokumentation gibt es ja drei zusätzliche Dokumente zum Logging und im „Basic Tutorial” steht ziemlich am Anfang wann Logging sinnvoll ist, und welches Level für welche Art von Ausgaben. Da würde ich sagen das INFO eigentlich noch etwas ist, was man gerne in einer Logdatei haben möchte. Wenn das zu viel ist, gibt man dort vielleicht Sachen aus die eher für DEBUG gedacht waren. Und wenn es nur einzelne Logger sind, die einem zu viel Infos liefern, kann man ja auch gezielt bei denen INFO abschalten. Minimal würde ich nicht ERROR sondern WARNING setzen. Wenn man das sinnvoll einsetzt, kann das bei einem ERROR vielleicht Hinweise für den Grund liefern.

Ad 2: Bei ``try``/``except`` ist die Versuchung oft gross Ausnahmen zu behandeln, an Stellen an denen man nicht sinnvoll darauf reagieren kann. Man muss sich dabei immer klar machen, dass das Programm nach dem ``except`` weiter läuft, und sich fragen, ob es das in dem Zustand in dem es dann ist, überhaupt kann. Wenn dann irgendwelche Daten fehlen, weil beispielsweise eine Datei nicht gelesen werden konnte, oder wenn eine Socket-Verbindung nicht hergestellt werden konnte, dann kann man eine sinnvolle Behandlung erst weiter ”oben” machen als in der Funktion/Methode in der die Datei gelesen oder die Verbindung hergestellt werden sollte. Wenn man eine Ausnahme nicht behandeln kann, sollte man das auch nicht tun. Bei Ausnahmen die man nicht kennt, oder von denen man nicht weiss, das sie bei einer bestimmten Operation auftreten können, kann man in der Regel auch nicht sagen wie man die sinnvoll behandeln kann, oder ob die Behandlung die man bereits für bekannte Ausnahmen geschrieben hat, auch für andere sinnvoll ist.

Darum ist das einzig sinnvolle was man da tun kann, entweder gar nichts, wenn man das Programm bei einem unbekannten Fehler sowieso nur abbrechen würde, oder sicherstellen, dass es wirklich probemlos möglich ist eine Ausnahme zu ignorieren, diese dann aber mindestens irgendwo speichern oder ausgeben lassen. Sonst kann man sich dumm und dusselig suchen wenn etwas nicht funktioniert, Ausnahmen aber einfach ”lautlos” ignoriert werden. Da ist `logging` und `exception()` sehr praktisch.
Black Panther
User
Beiträge: 27
Registriert: Samstag 11. Juni 2016, 19:09

Hallo,

kurze Frage zu User Inputs über Keyboard oder Scanner. Die normale und gängige Methode scheint es über raw_input() zumindest bei Python 2.7 so, den Input aufzugreifen. Automatisch wird aber alles was ich vorher eingegeben habe auch mit aufgegriffen. Gibt es eine Möglichkeit den Speicher zu löschen?
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@Black Panther: das hat jetzt nicht wirklich etwas mit der ursprünglichen Frage zu tun.
Normalerweise will man ja nicht, dass Eingaben verloren gehen. Das heißt, man macht irgendetwas, währenddessen kann der Nutzer schon etwas eingeben und irgendwann wird per raw_input() die Daten gelesen. Ich dachte, Du willst das ganze headless betreiben, so dass eigentlich nur Daten vom Scanner kommen. Und auch falls nicht, so kann der Nutzer immer noch Kommandos eingeben, die irgendetwas bewirken. Warum willst Du also den Speicher löschen?
Black Panther
User
Beiträge: 27
Registriert: Samstag 11. Juni 2016, 19:09

@Sirius3 ...ich wollte einfach keinen weiteren Thread eröffnen. In der Tat hast du Recht, wenn du davon ausgehst, dass der Usser durch den Scanner Eingaben bei mir tätigt. Warum funktioniert raw_input() nicht zu dem Zeitpunkt der Abfrage, sondern zeichnet alles auf was der User auch schon vorher eingibt, während andere Funktionen von mir ablaufen?
SO wäre es möglich ein Haufen Serienummern einzuscannen und dann würde bei raw-Input() nur unverständliches übergeben werden.
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@Black Panther: normalerweise sollte der User gar keine Möglichkeit haben einen Haufen Seriennummern einzuscannen, weil das Abarbeiten normalerweise so kurz ist, dass das Programm gleich wieder in raw_input hängt und umgekehrt wäre es ja blöd, wenn der Nutzer etwas scannt, das Programm aber gerade für eine Millisekunde nicht bereit ist, und deshalb die Eingabe verwirft. Der Scanner sollte eigentlich klar abgetrennte Seriennummern senden, so dass nichts unverständliches gelesen wird, sondern nur ein Haufen Seriennummern, und falls doch etwas unverständliches kommt, sollte das Programm darauf reagieren können, z.B. in dem es nervös rot blinkt und die Anfrage dann ignoriert.
Black Panther
User
Beiträge: 27
Registriert: Samstag 11. Juni 2016, 19:09

@Sirius3....ich kann alles nachvollziehen was du mir schilderst.
Fakt ist: Es kommt ein Sensor zum Einsatz, wenn der nicht betätigt ist wartet nun einmal das Programm. In der Zeit ist es möglich das der User aus unsinniger Art und Weise heraus etwas einscannt (vielleicht auch vermehrt). Meine Frage noch einmal konkretisiert: Wie kann man den Speicher auf den raw_input() zurückgreift kurz vorher löschen? Sodass nur auf die konkrete Nachfrage eine Eingabe beachtet wird. Das ist ein sehr elementares Problem, was schon im deutschen und englischen Raum scharf diskutiert wurde.


Leider ist mir keine Lösung bisher entgegen geflogen, so dass ich nach Hilfe fragen muss.
Antworten