Hallo Leute,
ich sitze derzeit an einem kleinen Projekt und zwar möchte ich mithilfe des UDP Sockets in Python zwei Teilprozesse, die natürlich miteinander kommunizieren können. Und zwar möchte ich am Ende mithilfe dessen einen Sinusverlauf erstellen. Ich möchte, dass der erste Prozess Zeit und Amplitude an den zweiten Prozess weitergibt und das schrittweise. Und der zweite Prozess soll die Daten aufnehmen und dann die Punkte plotten. Leider habe ich da ein paar Schwierigkeiten und würde mich über Tipps von euch freuen
Was ich bisher habe:
- Erster Prozess:
import socket
import numpy as np
import matplotlib.pyplot as plot
import pickle
if __name__ == "__main__":
host = "127.0.0.1"
port = 4455
addr = (host, port)
HEADERSIZE = 10
# Create a UDP socket at client side
UDPClientSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# Send to server using created UDP socket
time = 0
data = dict()
data['time'] = []
data['amplitude'] = []
while True:
amplitude = np.sin(time)
data['time'].append(time)
data['amplitude'].append(amplitude)
msg = pickle.dumps(data)
print(f'{len(msg)}')
print(f'{len(msg):<{HEADERSIZE}}')
msg = bytes(f'{len(msg):<{HEADERSIZE}}', 'utf-8') + msg
time = time + 0.1
UDPClientSocket.sendto(msg, addr)
msg, addr = UDPClientSocket.recvfrom(2048)
print(f"Server: {msg}")
- Zweiter Prozess:
import socket
import numpy as np
import matplotlib.pyplot as plot
import pickle
if __name__ == "__main__":
host = "127.0.0.1"
port = 4455
HEADERSIZE = 10
# Create a datagram socket
UDPServerSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# Bind to address and ip
UDPServerSocket.bind((host, port))
print("UDP server up and listening")
# Listen for incoming datagrams
while True:
msg, addr = UDPServerSocket.recvfrom(2048)
print(f"Client: {msg}")
# msg entpacken
msg = pickle.dumps(msg).decode()
plot.plot(msg)
# Give a title for the sine wave plot
plot.title('Sine wave')
# Give x axis label for the sine wave plot
plot.xlabel('Time')
# Give y axis label for the sine wave plot
plot.ylabel('Amplitude = sin(time)')
plot.grid(True, which='both')
plot.axhline(y=0, color='k')
# Display the sine wave
plot.show()
# Sending a reply to client
UDPServerSocket.sendto(msg, addr)
Wenn ich das so ausführe, wird mir folgende Fehlermeldung angezeigt: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte
Ich würde mich mega freuen, wenn mir da jemand helfen könnte.
UDP Socket Projekt - Sinusfunktion
Das ist alles Gurke. Warum baust du ein Protokoll mit Länge und dann pickle, obwohl UDP message basiert immer eine vollständige Nachricht liefert? Die dekodierung deines Protokolls im Server fehlt dann aber. Und zweimal dumps ist auch falsch. Du musst einmal loads nutzen. Ein decode danach ist auch Quatsch, die Nachricht ist ja typisiert. Zu guter letzt: warum der Rückkanal, und wenn der nötig ist, warum dann kein TCP?
Habe meinen Code noch einmal überarbeitet, weil wie du schon sagst das alles irgendwie keinen Sinn ergeben (bin seit einem Monat mit Python am arbeiten, deswegen nicht zu streng sein )__deets__ hat geschrieben: ↑Montag 9. Mai 2022, 14:58 Das ist alles Gurke. Warum baust du ein Protokoll mit Länge und dann pickle, obwohl UDP message basiert immer eine vollständige Nachricht liefert? Die dekodierung deines Protokolls im Server fehlt dann aber. Und zweimal dumps ist auch falsch. Du musst einmal loads nutzen. Ein decode danach ist auch Quatsch, die Nachricht ist ja typisiert. Zu guter letzt: warum der Rückkanal, und wenn der nötig ist, warum dann kein TCP?
Nur habe ich jetzt eine neue Fehlermeldung, vielleicht kannst du mir da auch weiterhelfen: _pickle.UnpicklingError: could not find MARK
Ich habe den Code jetzt noch einmal komplett umgeändert. Der sieht jetzt folgendermaßen aus:
-Server:
import socket
import numpy as np
import matplotlib.pyplot as plot
import pickle
if __name__ == "__main__":
host = "127.0.0.1"
port = 4455
HEADERSIZE = 10
# Create a socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# Bind to address and ip
s.bind((host, port))
s.listen()
print("UDP server up and listening")
conn, addr = s.accept()
# Listen for incoming datagrams
with conn:
print(f'Connected by {addr}')
while True:
received = conn.recv(4096)
print(f"Client: {received}")
# msg entpacken
data_variable = pickle.loads(received)
print(data_variable)
plot.plot(data_variable)
# Give a title for the sine wave plot
plot.title('Sine wave')
# Give x axis label for the sine wave plot
plot.xlabel('Time')
# Give y axis label for the sine wave plot
plot.ylabel('Amplitude = sin(time)')
plot.grid(True, which='both')
plot.axhline(y=0, color='k')
# Display the sine wave
plot.show()
- Client:
import socket
import numpy as np
import matplotlib.pyplot as plot
import pickle
import time
if __name__ == "__main__":
host = "127.0.0.1"
port = 4455
addr = (host, port)
HEADERSIZE = 10
# Create a UDP socket at client side
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((host, port))
# Send to server using created UDP socket
time = 1
data = dict()
data['time'] = []
data['amplitude'] = []
while True:
amplitude = np.sin(time)
data['time'].append(time)
data['amplitude'].append(amplitude)
msg = pickle.dumps(data)
print(f'{len(msg)}')
print(f'{len(msg):<{HEADERSIZE}}')
msg = bytes(f'{len(msg):<{HEADERSIZE}}', 'utf-8') + msg
time = time + 0.1
s.send(msg)
print(f"Server: {msg}")
Dennoch wird mir weiterhin auf Serverseite der oben genannte Fehler angezeigt (data_variable = pickle.loads(data)
_pickle.UnpicklingError: could not find MARK)
Bitte setz den Code doch in Code-Tags. Die erscheinen automatisch, wenn du im vollständigen Editor den </>-Button drückst. Zwichen die Tags gehört der Code.
So geht die Einrückung verloren - und die ist bei Python nun einmal wichtig.
So geht die Einrückung verloren - und die ist bei Python nun einmal wichtig.
Code: Alles auswählen
[code]
Danke für den Tipp
Server:
Code: Alles auswählen
import socket
import numpy as np
import matplotlib.pyplot as plot
import pickle
if __name__ == "__main__":
host = "127.0.0.1"
port = 4455
HEADERSIZE = 10
# Create a socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# Bind to address and ip
s.bind((host, port))
s.listen()
print("UDP server up and listening")
conn, addr = s.accept()
# Listen for incoming datagrams
with conn:
print(f'Connected by {addr}')
while True:
received = conn.recv(4096)
print(f"Client: {received}")
# msg entpacken
data_variable = pickle.loads(received)
print(data_variable)
plot.plot(data_variable)
# Give a title for the sine wave plot
plot.title('Sine wave')
# Give x axis label for the sine wave plot
plot.xlabel('Time')
# Give y axis label for the sine wave plot
plot.ylabel('Amplitude = sin(time)')
plot.grid(True, which='both')
plot.axhline(y=0, color='k')
# Display the sine wave
plot.show()
Code: Alles auswählen
import socket
import numpy as np
import matplotlib.pyplot as plot
import pickle
import time
if __name__ == "__main__":
host = "127.0.0.1"
port = 4455
addr = (host, port)
HEADERSIZE = 10
# Create a UDP socket at client side
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((host, port))
# Send to server using created UDP socket
time = 1
data = dict()
data['time'] = []
data['amplitude'] = []
while True:
amplitude = np.sin(time)
data['time'].append(time)
data['amplitude'].append(amplitude)
msg = pickle.dumps(data)
print(f'{len(msg)}')
print(f'{len(msg):<{HEADERSIZE}}')
msg = bytes(f'{len(msg):<{HEADERSIZE}}', 'utf-8') + msg
time = time + 0.1
s.send(msg)
print(f"Server: {msg}")
Da sind doch immer noch die gleichen Probleme drin. Jetzt benutzt du ploetzlich TCP, schreibst aber noch von UDP. Dann brauchst du auch ein Protokoll, dass du beim schreiben auch mit deinem headersize erzeugst. Aber du liest das nicht ein, sonder versuchst schon wieder direkt die gelesenen Daten zu deserialisieren. Natuerlich geht das nicht. Pickle hat ein wohldefiniertes Format, das nicht einfach mit beliebigen Bytes zu Beginn zurecht kommt.
Entweder du
- benutzt UDP
- schickst NUR pickle daten, keine HEADERSIZE-Gedoens
- deserialisiert diese Nachrichten mit pickle.
Oder du
- benutzt TCP
- benoetigst zwingend(!!!!!) ein Protokoll, wie zb eine Zeile mit der Angabe in Bytes, die dann folgend einzulesen sind. Gefolgt vom pickle dump.Und musst das auch befolgen, Zustandsmaschine und Verwendung von sendall inklusive.
- extrahierst dann den eigentlichen Datenblock aus einer eingehenden Kommunikation, und deserialisiertst den dann mit pickle.
Um das nochmal ganz deutlich zu sagen, falls die 5 Ausrufezeichen nicht deutlich genug waren: TCP ist NICHT nachrichtenorientiert! Das ist ein *STROM* von Bytes, der an einer *beliebigen* Stelle unterbrochen werden kann, und dann kommt ein naechstes Paket mit dem Rest. Darum *MUSS* man ueber TCP ein Protokoll fahren! Sonst geht es nicht!
Entweder du
- benutzt UDP
- schickst NUR pickle daten, keine HEADERSIZE-Gedoens
- deserialisiert diese Nachrichten mit pickle.
Oder du
- benutzt TCP
- benoetigst zwingend(!!!!!) ein Protokoll, wie zb eine Zeile mit der Angabe in Bytes, die dann folgend einzulesen sind. Gefolgt vom pickle dump.Und musst das auch befolgen, Zustandsmaschine und Verwendung von sendall inklusive.
- extrahierst dann den eigentlichen Datenblock aus einer eingehenden Kommunikation, und deserialisiertst den dann mit pickle.
Um das nochmal ganz deutlich zu sagen, falls die 5 Ausrufezeichen nicht deutlich genug waren: TCP ist NICHT nachrichtenorientiert! Das ist ein *STROM* von Bytes, der an einer *beliebigen* Stelle unterbrochen werden kann, und dann kommt ein naechstes Paket mit dem Rest. Darum *MUSS* man ueber TCP ein Protokoll fahren! Sonst geht es nicht!
Da mir das mit dem message header komisch vorkam, habe ich mal danach gesucht. Und das hier gefunden: https://pythonprogramming.net/pickle-ob ... -python-3/
Da macht er das doch richtig. Es ist ein bisschen konvolut, aber er liest den Header ein, und vor allem macht er das hier:
Er respektiert also genau den header, und schneidet den *vor* dem deserialisieren ab.
Warum folgst du dem Tutorial nicht in gaenze?
Da macht er das doch richtig. Es ist ein bisschen konvolut, aber er liest den Header ein, und vor allem macht er das hier:
Code: Alles auswählen
print(pickle.loads(full_msg[HEADERSIZE:]))
Warum folgst du dem Tutorial nicht in gaenze?
ok, ich muss mich korrigieren. Was der da veranstaltet ist natuerlich auch schon wieder grober Unfug, weil er die Daten immer in 16 Byte Bloecken einliest. Wehe da werden mal zwei Pakete schnell hintereinander verschickt, dann landen ersten 4 Bytes des zweiten Pakets im letzten Block des ersten, und das ganze Kartenhaus faellt zusammen, weil er auf immer und ewig mehr daten erwartet. Denn er prueft ja mit ==, ob die Nachricht in Gaenze empfangen wurde.
Da draussen ist wirklich fast nur Sch*isse zu finden, was Netzwerkprogrammierung angeht. Wenn es keinen Grund gibt, warum du das Rad neu erfinden willst, kann ich dir nur mit Nachdruck zu existierenden Bibliotheken wie ZeroMQ, nanoms odr nng (persoenliche Wahl), und HTTP servern raten.
Da draussen ist wirklich fast nur Sch*isse zu finden, was Netzwerkprogrammierung angeht. Wenn es keinen Grund gibt, warum du das Rad neu erfinden willst, kann ich dir nur mit Nachdruck zu existierenden Bibliotheken wie ZeroMQ, nanoms odr nng (persoenliche Wahl), und HTTP servern raten.
- __blackjack__
- User
- Beiträge: 13236
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Was man auch machen könnte ist sich die TCP-Verbindung in ein Dateiobjekt zu verpacken, Socket-Objekte haben da eine Methode für (`makefile()`), und einfach `pickle.load()` verwenden, denn die Pickledaten selbst enthalten auch die nötigen Informationen über die Länge und `pickle.load()` hört auf zu lesen wenn die Daten von einem ”Pickle” komplett sind.
Please call it what it is: copyright infringement, not piracy. Piracy takes place in international waters, and involves one or more of theft, murder, rape and kidnapping. Making an unauthorized copy of a piece of software is not piracy, it is an infringement of a government-granted monopoly.