Guten Morgen!
Nach dem Einschalten eines Raspberry Zeros wird per 'cron daemon' die
AtBoot.sh ausgeführt(1). 'webserver.py' startet, UDPServer.py nicht.
Beide habe die gleichen Rechte(2, 3, 4).
Das Aufrufen von der Kommandozeile startet den UDP-Server einwandfrei.
Thomas W. schrieb:> bei /home/pi/python/UDPServer.py fehlt der Befehlsinterpreter, vulgo> #!/usr/bin/python3
Da der Name des Interpreters python3 vor jedem Python-Skript in der
AtBoot.sh steht und das Ausführen von AtBoot.sh von der Kommandozeile
funktioniert, kann das nicht sein. Habe die Zeile zum Testen trotzdem
hinzugefügt. Das Ergebnis ist wie erwartet, der UDPServer nicht startet.
Der Haken muss irgendwo anders sein.
Manfred schrieb:> Thomas W. schrieb:>>> bei /home/pi/python/UDPServer.py fehlt der Befehlsinterpreter, vulgo>> #!/usr/bin/python3>> Da der Name des Interpreters python3 vor jedem Python-Skript in der
Du hast Recht, ich bin noch nicht da...
Gruesse
Th.
Du schreibst in deinem UDP-Server auf STDOUT. Kann es sein, dass das
nicht mehr verfügbar ist, wenn's aus der AtBoot gestartet wird?
versuch mal
>> python3 /home/pi/python/UDPServer.py > /home/pi/udp-server.log
oder
>> screen -dmS UDPsever python3 /home/pi/python/UDPServer.py
im atboot.
Hallo Manfred,
Manfred schrieb:> Nach dem Einschalten eines Raspberry Zeros wird per 'cron daemon' die> AtBoot.sh ausgeführt(1). 'webserver.py' startet, UDPServer.py nicht.
Wir könnten jetzt natürlich anfangen, Deinen Code zu debuggen und zum
Beispiel erstmal ein anständiges Logging (jede
Python-Standardinstallation bietet dazu das Modul "logging") in Deinen
Code einzubauen. Aber um ganz ehrlich zu sein, widerstrebt mir das, denn
an Deinem Ansatz ist so viel Unelegantes und Krudes... es erscheint mir
sinnvoller, die Angelegenheit grundsätzlicher anzugehen, so daß sie
langfristig funktionieren kann.
Langlebige Prozesse mit Crons @reboot-Feature zu starten ist möglich,
aber maximal unelegant. Eleganter ist es, für Deine beiden Prozesse
jeweils ein systemd-Unitfile anzulegen, so daß sich systemd um das
Management Deiner Prozesse kümmern und sie starten und stoppen, sich um
das Logging kümmern, sie monitoren und gegebenenfalls restarten kann.
Nebenbei scheinst Du zu versuchen, die Dinge möglichst schnell und
einfach zu lösen, anstatt die Sache richtig zu machen. Ich nehme das an,
weil Du UDP benutzt, was nur in wenigen begründeten Ausnahmen eine gute
Idee ist, aber von Einsteigern gerne benutzt wird, weil es ihnen
zunächst einfacher erscheint. Zudem schreibst Du Dein UDP-Skript direkt
mit dem Modul socket, anstatt die in der Python-Standardinstallation
bereits fertig vorhandene Klasse UDPServer aus dem Modul socketserver zu
verwenden. Offensichtlich hast Du Dich also nicht sonderlich tief in die
Möglichkeiten der Python-Library eingearbeitet... so sieht das
jedenfalls für mich aus. Aber sehen wir uns mal Dein UDP-Skript etwas
genauer an.
Da ist keine Schleife im UDP-"Server", Fehler werden unterdrückt --
except ohne explizite Angabe der abzufangenden Exception ist keine gute
Idee, und für ein except: pass müßte man schon extrem triftige Gründe
haben. Zudem sendest Du zuerst Daten (sock.sendto()) an den Port Deines
Skripts, dann versuchst Du Daten zu lesen (sock.recvfrom())... an dieser
Stelle sind die Daten, die Du gerade an den Port versendet hast, aber
ohnehin schon längst im Nirvana verschwunden. Dann läuft Dein UDP-Skript
in den zuvor gesetzten Timeout (sock.settimeout()), aber anstatt diesen
Fehler (oder idealerweise den kompletten Traceback mit der Funktion
print_exc() aus dem Standardmodul traceback) auszugeben, verschluckst
und unterdrückst Du ihn. Darum glaube ich, daß Dein UDP-Skript zwar
korrekt gestartet wird, sich nach Ablauf des Socket-Timeout aber (wegen
Deiner Fehlerunterdrückung stillschweigend) gleich wieder völlig korrekt
beendet.
Machen wir es kurz: das, was Du da bisher gemacht hast, ist leider nicht
ansatzweise sinnvoll, und selbst dann, wenn Du es irgendwann ans Laufen
bekommst, wird es Dir langfristig auf die Füße fallen. Vielleicht fangen
wir die Sache daher mal konstruktiv an, indem Du uns erzählst, was Du da
eigentlich vorhast -- also: warum Du einen HTTP- und einen UDP-Server
starten willst, und was sie ganz konkret tun sollen ("soll HTTP-Anfragen
bedienen" ist keine sinnvoll Erklärung, sorry). Und dann überlegen wir
gemeinsam eine konstruktive Lösung, was meinst Du?
Der UDP-Server gibt noch was auf die Konsole aus. Vielleicht liegts
daran. Es ist generell schlechter Stil, Prozesse im Hintergrund
auszuführen, ohne ihre Standard-Ausgabe in irgendein File umzuleiten.
Und sei es /dev/null. Also z.B.
Noch besser wäre es, wenn man die Distributions-Infrastruktur richtig
benutzen würde. Also z.B. start-stop-daemon. Und am besten wäre, wenn
man eine systemd-Unit oder zumindest ein init-Script dafür verwenden
würde.
Ach ja. Das Thema ist hier unpassend. "PC-Hard- und Software" würde
besser passen. Am Ende des Tages ist der RasPi ein PC.
Εrnst B. schrieb:> Du schreibst in deinem UDP-Server auf STDOUT. Kann es sein, dass das> nicht mehr verfügbar ist, wenn's aus der AtBoot gestartet wird?
STDOUT sollte noch verfügbar sein, das wird ja beim Start des Skripts im
Hintergrund vom aufrufenden Prozeß übernommen. Der ist AtBoot.sh, und
das bekommt STDOUT vom Cron-Daemon -- der dann alles, was auf dieses
STDOUT geschrieben wird, in eine Mail einpackt, die entweder an "root"
oder an einen in der Umgebungsvariable MAIL konfigurierten User sendet.
Thomas W. schrieb:> bei /home/pi/python/UDPServer.py fehlt der Befehlsinterpreter, vulgo> #!/usr/bin/python3
Deswegen ruft der TO das Teil explizit mit "python3 <skript>" auf, dann
braucht er keine Shebang-Zeile. Ansonsten wäre "#!/usr/bin/env python3"
oder "#!/usr/bin/env python" besser, dann funktioniert die Veranstaltung
auch in virtualenv, venv und Ähnlichem.
Der Pythonische Weg wäre der Context Manager, den open() zurückgibt:
1
with open('/home/pi/index/ramdisk/temps.txt', 'a') as ofh:
2
ofh.write(ClientData.decode('utf-8') + ...)
Damit wird die Datei automatisch geschlossen. Wohlerzogene Pythonistas
verzichten in Variablennamen auf Großbuchstaben, statt ClientData würde
Deine Variable nach PEP8 [1] client_data heißen. Leider halten sich
einige alten Python-Standardmodule wie das unten erwähnte
"logging"-Modul nicht vollständig an PEP8, sonst würde die Funktion
basicConfig basic_config heißen. Aber für neuen Code sollte man sich an
PEP8 halten, das macht das Leben deutlich einfacher und verhindert, daß
ein Mob mit Mistforken und Fackeln einen verfolgt. ;-)
Aber eigentlich willst Du ja ein Logging, dafür gibt es ein
Standardmodul mit dem total überraschenden Namen "logging":
1
import sys
2
import logging
3
4
logging.basicConfig(
5
format='%(asctime)s %(levelname)s %(message)s',
6
level=logging.DEBUG,
7
stream=sys.stderr # oder filename='temps.txt'
8
)
9
10
logging.info('Eine Logmessage mit dem Loglevel INFO')
Achtung: die Übergabe von Parameter an die logging-Funktionen geht etwas
anders als bei print(), die "faule Auflistung" mit Kommata ist in den
logging-Funktionen nicht möglich.
[1] https://peps.python.org/pep-0008/
@ Thomas
Das Verzeichnis /home/pi/index/ramdisk existiert.
@ Ernst
python3 /home/pi/python/UDPServer.py > /home/pi/udp-server.log
Die Log-Datei ist leer (0 Bytes).
@ Axel
python3 /home/pi/python/UDPServer.py >udp.log 2>&1 &
Ergebnis, die Log-Datei enthält diese Fehlermeldung:
1
Traceback (most recent call last):
2
File "/home/pi/python/UDPServer.py", line 15, in <module>
Es funktioniert.
Zwischen Aufruf des Webservers und des UDP-Servers habe ich ein
1
Sleep 100
eingefügt.
In einem Beitrag auf stackoverflow.com stand, dass das der Fehler
auftritt, wenn noch nicht alle Ressourcen von Linux freigegeben wurden.
Hier noch einmal die Fehlermeldung:
1
Traceback (most recent call last):
2
File "/home/pi/python/UDPServer.py", line 15, in <module>
Manfred schrieb:> Wer noch einen Hinweis auf den Fehlergrund hat, poste ihn bitte.
Du bindest den UDP-Server an eine spezifische IP-Adresse, nicht an
0.0.0.0?
Dann muss diese IP-Adresse auch vorhanden sein, wenn der Server startet.
Falls dein RasPi seine IP per DHCP bekommt, oder das AtBoot.sh sehr früh
startet, ist das nicht gegeben.
Schau dir nochmal an, was oben zum Thema systemd-unit geschrieben wurde.
Damit kannst du solche Abhängigkeiten und damit die Startreihenfolge
elegant festlegen.