Hallo,
kann mir jemand einen Tipp geben?
Ich habe im Netz 1mio beispiele gefunden für client-server (echo) anwendungen, leider habe ich eine andere Anwendung vor.
Ich will ein Konsolen-Programm schreiben, dass UDP sendet(per usereingabe) und gleichzeitig immer schaut ob UDP SIgnale reinkommen. (Fernsteuerung)
Vermutlch threadbasiert: 1 thread hört, einer sendet.
Ist socketserver.ThreadingMixIn das was ich dafü brauche und wenn ja, wie verwende ich es?
Netzwerk ist neu für mich.
Client soll drucgehend lauschen
Ergänzung
Beide Sockets sollen im selben Netzwerk sein. Ohne Verschlüsselung und alles - ganz simpel.
Einfach nur UDP Nachrichten an einen Server schicken und immer höhren ob was reinkam von dem Server. Jedoch halt IMMER danach hören, da auch ohne Nutzereingabe nachrichten vom server kommen können.
Beide Sockets sollen im selben Netzwerk sein. Ohne Verschlüsselung und alles - ganz simpel.
Einfach nur UDP Nachrichten an einen Server schicken und immer höhren ob was reinkam von dem Server. Jedoch halt IMMER danach hören, da auch ohne Nutzereingabe nachrichten vom server kommen können.
Kann man mit Threads machen. Kann man aber je nach gewuenschter Benutzeroberflaeche auch besser machen. Womit programmierst du die?
Ich habe im uebrigen fuer solche Dinge in der Vergangenheit stattdessen nanomsg benutzt, und das wuerde ich auch hier empfehlen. Damit kannst du eine bi-direktionale PAIR-Verbindung aufmachen, es ist auch egal, ob client und server mal abschmieren, es verbindet sich alles automagisch neu, und im Gegensatz zu normalen sockets kann man auch periodisch pollen, wenn das einfacher sein sollte - ohne auf Threads zurueckgreifen zu muessen. Im Hintergrund werkeln da auch welche, aber damit muss man sich nicht rumscheren.
Ich habe im uebrigen fuer solche Dinge in der Vergangenheit stattdessen nanomsg benutzt, und das wuerde ich auch hier empfehlen. Damit kannst du eine bi-direktionale PAIR-Verbindung aufmachen, es ist auch egal, ob client und server mal abschmieren, es verbindet sich alles automagisch neu, und im Gegensatz zu normalen sockets kann man auch periodisch pollen, wenn das einfacher sein sollte - ohne auf Threads zurueckgreifen zu muessen. Im Hintergrund werkeln da auch welche, aber damit muss man sich nicht rumscheren.
@W33Z: Das ist auch gut so, da 999957 der Beispiele Schrott sind.
Für UDP möchtest Du wahrscheinlich socketserver.ThreadingUDPServer verwendet. Was verstehst Du am Beispiel in der Dokumentation nicht?
Bist Du sicher, dass Du UDP verwenden möchtest?
Für UDP möchtest Du wahrscheinlich socketserver.ThreadingUDPServer verwendet. Was verstehst Du am Beispiel in der Dokumentation nicht?
Bist Du sicher, dass Du UDP verwenden möchtest?
- __blackjack__
- User
- Beiträge: 13116
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@W33Z: Um die letzte Frage von Sirius3 noch ein bisschen zu präzisieren: Dir ist klar das bei UDP Pakete auch einfach verloren gehen können?
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
danke an euch alles schonmal an die Anteilnahme
Ja ich kenne UDP, also die Eigenschaften. Wenn mal ein Paket verloren geht, ist das halt so. Das ist nicht schlimm. Dann bekommt man keine antwort und weiß, das signal kam nicht an. Es soll ganz simpel und verbindungslos sein.
https://docs.python.org/3.4/library/socketserver.html
auf der Seite gibts ein Beispiel. Es wird ein server erstellt, der für jede Nachricht eines clienten ein thread aufmacht und die nachricht zurückschickt. Da ich mit threads auch noch nichts am hut hatte, wollte ich die komplexität klein halten und auch keine extra lib downloaden.
Ich würde einfach nur gern einen Listener haben, der immer horscht ob ein SIgnal reinkommt (das würde ich unter dem requestHandler verstehen)
und gleichzeitig sollen Nutzereingaben möglich sein - also signale per UDP verschicken.
Ich lerne immer gut an Beispielen, nur find ich dazu nichts im Netz - das irgendwie in die Richtung geht - meiner Meinung nach (ich bin kein Profi)
Ja ich kenne UDP, also die Eigenschaften. Wenn mal ein Paket verloren geht, ist das halt so. Das ist nicht schlimm. Dann bekommt man keine antwort und weiß, das signal kam nicht an. Es soll ganz simpel und verbindungslos sein.
https://docs.python.org/3.4/library/socketserver.html
auf der Seite gibts ein Beispiel. Es wird ein server erstellt, der für jede Nachricht eines clienten ein thread aufmacht und die nachricht zurückschickt. Da ich mit threads auch noch nichts am hut hatte, wollte ich die komplexität klein halten und auch keine extra lib downloaden.
Ich würde einfach nur gern einen Listener haben, der immer horscht ob ein SIgnal reinkommt (das würde ich unter dem requestHandler verstehen)
und gleichzeitig sollen Nutzereingaben möglich sein - also signale per UDP verschicken.
Ich lerne immer gut an Beispielen, nur find ich dazu nichts im Netz - das irgendwie in die Richtung geht - meiner Meinung nach (ich bin kein Profi)
Der UDPServer ist prinzipiell geeignet. Du musst den halt in deinen mainloop integrieren. Oder einen Thread starten. Weniger Komplexitaet geht nicht. Ausser man benutzt externe Bibliotheken, aber das willste ja nicht
Danke für eure ANtworten, ich habs:
Jetz wollte ich einen Schritt weiter als geplant gehen. Ich möchte gern die empfangenen Daten aus dem "Handler" raus bekommen, also nicht nur auf der Konsole ausgeben sondern diese außerhalb der Klasse in einer Variablen zur verfügung haben. Was ist da der beste Weg ?
Code: Alles auswählen
import socket
import threading
import socketserver
import sys
class myRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
self.data = self.request[0].strip()
print(self.data)
class ThreadedUDPServer(socketserver.ThreadingMixIn, socketserver.UDPServer):
pass
class steuerungLampe():
def __init__(self, ipLight, portLight):
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.s.bind(('',0))
ipAddr = socket.gethostbyname(socket.gethostname())
port = self.s.getsockname()[1]
self.server = ThreadedUDPServer((ipAddr, port),myRequestHandler)
self.ipLight = ipLight
self.portLight = portLight
server_thread = threading.Thread(target=self.server.serve_forever)
server_thread.daemon = True
server_thread.start()
# sende daten
def sendData(self, message):
sent = self.s.sendto(str.encode(message), (self.ipLight, self.portLight))
# schließe socket und thread
def closeListener(self):
self.s.shutdown()
self.server.shutdown()
self.server.server_close()
steuerung = steuerungLampe('192.168.178.1', 1000)
while True:
message = input()
steuerung.sendData(message)
Du musst zuerst ein bisschen aufraeumen. Dazu gehoert
- sinnlose "my"-Praefixe loswerden.
- SteuerungLampe statt steuerungLampe benutzen. In Python schreibt man Klassennamen CamelCase, nicht dromedarCase
- globale Variablen steuerung, message muessen verschwinden. Stattdessen eine main-Funktion einfuehren, und die aufrufen. IN der main-Funktion liegst du dann steuerung und message an.
- da kannst du dann auch eine Instanz einer Queue aus dem queue-Modul erzeugen. Die uebergibst du dann an SteuerungLampe als Argument im Konstruktor.
- die SteuerungLampe erzeugt dann den UDP-Server mit einer kleinen Aenderung: statt direkt die Klasse RequestHandler (ohne sinnlosen my-Praefix) anzugeben, gibst du stattdessen eine Factory-Funktion an, die du mit dem functools.partial und RequestHandler baust. Die bekommte die Queue-Instanz angebunden. Dadurch werden nun alle RequestHandler mit dieser Queue versorgt.
- RequestHandler bekommt einen Konstruktor, in dem es sich die uebergebene message_queue merkt, und natuerlich den Konstrukter der Oberklasse aufruft. Und wenn jetzt Daten ankommen, stopfst es die in die Queue.
- in der Hautpschleife kannst du vor input pruefen, ob es Nachrichten gibt in der Queue. Und die dann bei Bedarf rausholen. Siehe dazu die Dokumentation zu queue.Queue.get.
- sinnlose "my"-Praefixe loswerden.
- SteuerungLampe statt steuerungLampe benutzen. In Python schreibt man Klassennamen CamelCase, nicht dromedarCase
- globale Variablen steuerung, message muessen verschwinden. Stattdessen eine main-Funktion einfuehren, und die aufrufen. IN der main-Funktion liegst du dann steuerung und message an.
- da kannst du dann auch eine Instanz einer Queue aus dem queue-Modul erzeugen. Die uebergibst du dann an SteuerungLampe als Argument im Konstruktor.
- die SteuerungLampe erzeugt dann den UDP-Server mit einer kleinen Aenderung: statt direkt die Klasse RequestHandler (ohne sinnlosen my-Praefix) anzugeben, gibst du stattdessen eine Factory-Funktion an, die du mit dem functools.partial und RequestHandler baust. Die bekommte die Queue-Instanz angebunden. Dadurch werden nun alle RequestHandler mit dieser Queue versorgt.
Code: Alles auswählen
self.server = ThreadedUDPServer((ipAddr, port), partial(RequestHandler, message_queue))
Code: Alles auswählen
class RequestHandler(socketserver.BaseRequestHandler):
def __init__(self, message_queue):
super().__init__()
self._queue = message_queue
def handle(self):
self._queue.put(self.request[0].strip())
Vielen Danke für die ganzen Tipps, ich habe auf die ganzen "Formatierungssachen" nicht so geachtet bis jetzt. Bin eigentlich kein Programmierer, bring mir das nebenbei seit dem Sommer bei.
Hab mir deine Ergänzungen angesehen (functools und queue) und auch in meinen Code aufgenommen, um die Stellen die du vorgeschlagen hast.
jetzt kommt nur folgende Fehlermeldung
Ich gehe davon aus, dass der Fehler im Konstruktor des RequestHandlers geworfen wird. (also klar der Fehler kommt aus de mSocketserver Modul, aber die stelle in meinem Code)
Im Zusammenhang mit der Vererbung und dem Aufruf "super()._init__()".
Er will nur request, client_address, doch was sind die 5 Argumente ((ipAddr, port),functools.partial(RequestHandler, message_queue)..und ?! )
Wenn ich das richtige sehe hat der BaseRequestHandler ein setup(), das denk ich gleichzusetzen ist mit __init__() - Diese macht im normalfall erstmal nichst laut doku (wenn man daran nichts tut) , daher frage ich mich, wie der Fehler kommt.
Hab mir deine Ergänzungen angesehen (functools und queue) und auch in meinen Code aufgenommen, um die Stellen die du vorgeschlagen hast.
jetzt kommt nur folgende Fehlermeldung
Code: Alles auswählen
Exception happened during processing of request from ('192.168.178.1', 64975)
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\socketserver.py", line 647, in process_request_thread
self.finish_request(request, client_address)
File "C:\ProgramData\Anaconda3\lib\socketserver.py", line 357, in finish_request
self.RequestHandlerClass(request, client_address, self)
TypeError: __init__() takes 2 positional arguments but 5 were given
Im Zusammenhang mit der Vererbung und dem Aufruf "super()._init__()".
Er will nur request, client_address, doch was sind die 5 Argumente ((ipAddr, port),functools.partial(RequestHandler, message_queue)..und ?! )
Wenn ich das richtige sehe hat der BaseRequestHandler ein setup(), das denk ich gleichzusetzen ist mit __init__() - Diese macht im normalfall erstmal nichst laut doku (wenn man daran nichts tut) , daher frage ich mich, wie der Fehler kommt.
Das ist die "Fehlermeldung" , diese kommt, wenn ich ein UDP Paket erhalte. Habe von einem anderen Rechner mir UDP Pakete schicken lassen un das kommt dann. Nicht mehr und nicht weniger
Also das Programm kompiliert und kann ausgeführt werden. Nur beim Emfangen wird statt die gesendete Nachricht der oben genannte Fehler angezeigt. Ich habe einfach den alten Code von mir genutzt um etwas zu senden.
Also das Programm kompiliert und kann ausgeführt werden. Nur beim Emfangen wird statt die gesendete Nachricht der oben genannte Fehler angezeigt. Ich habe einfach den alten Code von mir genutzt um etwas zu senden.
Code: Alles auswählen
import socket
import threading
import sys
import socketserver
import functools
import queue
class RequestHandler(socketserver.BaseRequestHandler):
def __init__(self, message_queue):
super().setup()
self._queue = message_queue
def handle(self):
self._queue.put(self.request[0].strip())
print(self.request[0].strip())
class ThreadedUDPServer(socketserver.ThreadingMixIn, socketserver.UDPServer):
pass
class SteuerungLampe():
def __init__(self, ipLight, portLight, message_queue):
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.s.bind(('',0))
ipAddr = socket.gethostbyname(socket.gethostname())
port = self.s.getsockname()[1]
self.handle = RequestHandler
self.server = ThreadedUDPServer((ipAddr, port),functools.partial(self.handle, message_queue))
self.ipLight = ipLight
self.portLight = portLight
server_thread = threading.Thread(target=self.server.serve_forever)
server_thread.daemon = True
server_thread.start()
# sende daten
def sendData(self, message):
sent = self.s.sendto(str.encode(message), (self.ipLight, self.portLight))
# schließe socket und thread
def closeListener(self):
self.s.shutdown()
self.server.shutdown()
self.server.server_close()
if __name__ == "__main__":
message_queue = queue.Queue()
steuerung = SteuerungLampe('192.168.178.1', 1000, message_queue)
while True:
receive = message_queue.get()
print(receive)
message = input()
steuerung.sendData(message)
Die Zuweisung an "self.handle" ist Unfug und verwirrend. Und im Konstruktor von RequestHandler rufst du nicht __init__ der Oberklasse auf. Sondern irgendeine Funktion "setup". Das ist falsch. Das muss __init__ sein.
Was ich aber vergessen habe ist, etwaige andere Parameter (die es offensichtlich gibt) weiter zu leiten:
Probier mal das.
Was ich aber vergessen habe ist, etwaige andere Parameter (die es offensichtlich gibt) weiter zu leiten:
Code: Alles auswählen
class RequestHandler(socketserver.BaseRequestHandler):
def __init__(self, message_queue, *args, **kwargs):
super().__init__(*args, **kwargs)
self._queue = message_queue