Probleme mit Socket-Programmierung
-
Hey,
Ich steuere meinen Mikrocontroller über Ethernet an. Diesen kann ich unter der IP: 192.168.0.10 über den Port 4555 erreichen. Klappt auch alles wunderbar.
Der Mikrocontroller empfängt über den Port 4555 und sendet die empfangen Dateien gleich wieder an dieselbe IP zurück auf dem Port 45175.Nun will ich eine 10mbyte große Datei über ethernet an meinen Mikrocontroller schicken mit pyhton:
1.Versuch war:
import socket,time datei=open("10_mb_file.txt","r") log=open("log.txt","w") #ip UPD_IP_Local="192.168.0.40" UPD_IP_Server="192.168.0.10" #ports UPD_Port_Listening= 45175 UPD_Port_Send= 45555 #create sockets sock_listening=socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock_listening.bind( (UPD_IP_Local,UPD_Port_Listening) ) sock_writing=socket.socket(socket.AF_INET, socket.SOCK_DGRAM) for line in datei: sock_writing.sendto(line, (UPD_IP_Server,UPD_Port_Send) ) data, addr = sock_listening.recvfrom(128) log.write(data) print "recivbe: %s" %data
Allerdings braucht der Mikrocontroller hier rund 33s, was ~317 kbyte/s entspräche. Das ist mir viel zu langsam, da der Mikrocontroller bis zu 100mbit/s unterstüzt.
Kann es sein dass es an meinem Python Programm liegt? Weil ich immer zeilenweise einlese? Vielleicht muss ich ja größere Strings auf einmal schicken?
Versuch 2:
Ein 50000 großen String 10000mal sendenimport socket,time #ip UPD_IP_Server="192.168.0.10" #ports UPD_Port_Send= 45555 sock_writing=socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock_writing.sendto("ahllo", (UPD_IP_Server,UPD_Port_Send) ) i=0 a=0 while a<=10000: s='hallo' a=a+1 i=0 while i<=50000: i=i+1 s=s+"i" #print s sock_writing.sendto(s, (UPD_IP_Server,UPD_Port_Send) )
Zeit: 83s
und nebenei auf den Port lauschen:
import socket def receive_test() : #Local ip UDP_IP="192.168.0.40" #Local port listening for packets UDP_PORT= 45175 #Create a socket sock = socket.socket( socket.AF_INET, # Internet socket.SOCK_DGRAM ) # UDP sock.bind( (UDP_IP,UDP_PORT) ) #Wait for data and print it. while True: data, addr = sock.recvfrom( 128 ) # buffer size is 1024 bytes print "received message: %s" % data receive_test()
Problem ist hier, dass er mir nichts anzeigt, da anscheinend der gesendete String zu groß ist?
Gibt es eine Möglichkeit, dass ich die ein-kommenden Dateien vom Socket, egal wie groß einfach in einen String oder ähnliches schreibe ?
Vielen Dank
-
Bei deiner ersten Variante sendest du eine Zeile zum µC, der schickt sie zurück und du empfängst sie. Erst danach wird die nächste Zeile gesendet.
Hier spielt auch die Zeilenlänge bzw die Anzahl Zeilen eine Rolle.Bei der zweiten Variante sendest du alles nacheinander und empfängst parallel dazu. Daher wird das Netz besser ausgelastet. (Hier kann man auch schön mit select beides in einem Programm machen.)
So große UDP-Pakete sind nicht unbedingt sinnvoll. Was die Implementierung des µC kann, solltest du am ehesten wissen. ("mein Mikrocontroller" => von dir programmiert?)
Versuch es halt mal mit kleineren Paketen. 512-Nutzbytes sollten eigentlich von jeder Implementierung verarbeitbar sein.
Edit:
Folgendes Program sendet immer Daten wenn es kann und empfängt immer Daten wenn sie anliegen. Sind alle Daten gesendet, beendet es sich. (Die letzten Pakete werden nicht wieder empfangen.)import socket,time,select serverIp = "192.168.0.10" answerUdpPort = 45175 serverUdpPort = 45555 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind(("", answerUdpPort)) data = 'x' * 512 sent = 0 countSent = 0 countRecv = 0 while sent < 10 * 1024 * 1024: readable, writable, exceptional = select.select([sock], [sock], [sock]) for s in readable: answer, addr = s.recvfrom(10240) countRecv = countRecv + 1 for s in writable: s.sendto(data, (serverIp, serverUdpPort)) sent = sent + len(data) countSent = countSent + 1 print "Sent: %i ;Recv: %i" %(countSent, countRecv)
Je nach Paketgröße ergeben sich unterschiedliche Übertragungsgeschwindigkeiten der Nutzdaten (in einem GBit LAN zwischen zwei PCs):
1 57 KiB/s
10 552 KiB/s
100 5.6 MiB/s
1000 54 MiB/s
10000 100 MiB/s
50000 100 MiB/s
-
Hey,
vielen lieben Dank für die Antwort.
Es ist nicht so ganz mein Mikrocontroller. Ich versuche nur ein Beispiel, diesen UPD-Ping Server welcher schon drauf ist zu verifizieren.
Nur Blick ich da allgemein noch nicht ganz durchZu deinem Beispiel:
.... data='x'*512 ....
Ich habe noch ein print eingefügt, damit ich die Ausgabe sehe:
Ausgabe:x.....x Sent: 20480 ;Recv: 6
dann habe ich folgendes geändert:
... data='x'*1024 ...
Ausgabe:
x....x Sent: 10486 ;Recv: 6
wenn ich
... date='x'*2000 ...
kommt folgendes:
Sent: 5243 ;Recv: 0
Kannst du mir kurz die letzte Ausgabe erklären? Schafft er es nicht 2000 Zeichen wieder zurück zu schicken oder wie?
-
Ich habe das Programm jetzt auf meine Bedürfnisse abgestimmt.
Ich möchte ja eine 10mbyte große Datei an den Mikrokontroller schicken und wieder empfangen.import socket,time,select,sys BUFFSIZE=1024 datei=open("10_mb_file.txt","r") log=open("log.txt","w") serverIp = "192.168.0.10" answerUdpPort = 45175 serverUdpPort = 45555 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind(("", answerUdpPort)) dateistring='' for line in datei: dateistring=dateistring+line data = 'x' * 512 sent = 0 countSent = 0 countRecv = 0 i=0 while i*BUFFSIZE<len(dateistring): tausend=0 sentstring='' while tausend<BUFFSIZE: sentstring=sentstring+dateistring[tausend+i*BUFFSIZE] tausend=tausend+1 readable, writable, exceptional = select.select([sock], [sock], [sock]) for s in readable: answer, addr = s.recvfrom(10240) log.write(answer) countRecv = countRecv + 1 for s in writable: s.sendto(sentstring, (serverIp, serverUdpPort)) countSent = countSent + 1 i=i+1 print "Sent: %i ;Recv: %i" %(countSent, countRecv)
Ausgabe nach Test:
Sent: 10240 ;Recv: 10237
Wieso fehlen mir empfangene Packete? Wie bekomme ich die her?
Das ganze läuft aber rasend schnell in ~4,2s
-
Wikipedia: User Datagram Protocol:
UDP ist ein verbindungsloses, nicht-zuverlässiges und ungesichertes wie auch ungeschütztes Übertragungsprotokoll.Du kannst dich also nicht darauf verlassen, dass alles, was du sendest auch ankommt. Und auch nicht, dass es in der selben Reihenfolge ankommt! (In einem kleinen LAN ist das zwar meistens der Fall, garantiert ist es aber nicht.)
Außerdem wird das Program beendet, sobald alles gesendet wurde. Das heißt am Ende sind noch Pakete "unterwegs", aber das Programm schon beendet.
select bietet einen Timeout. Du kannst also auch einfach noch warten und erst wenn 1s oder so nichtsmehr ankommt, das Programm beenden.
Das bei dem Test mit x…x kaum etwas ankam, kann einfach daran liegen, dass der µC nicht hinterher kam. In Kombination mit UDP kann es halt einen riesen Verlust darstellen.
Um die maximale Größe herauszufinden, kannst du immer ein Paket senden und mit der binären Suche je nachdem ob du eine Antwort bekommst oder nicht den Suchraum der Paketgrößen halbieren. (Bei ~2^16 Möglichkeiten kannst du aber auch einfach linear suchen.)