Hallo Allerseits,
ich habe folgendes Problem: Ich habe zum Testen einen einfachen Echoserver programmiert. Nun will ich mal ein jpeg echoen. Allerdings kann ich ja durch <sockname>.recv(<buffer>) nur eine bestimmte Anzahl an Bytes aus dem Socket abrufen. Den Buffer aus einfach riesig zu machen ist Performancetechnisch nicht optimal. Also habe ich die recv-Zeile des Servers in eine Schleife gepackt.
while 1:
<sockname>.recv(1024)
<echocode>
Das funktioniert im blocking-Mode wunderbar. Nun muss aber auch der Client wieder sämtliche zurückgeschickten Daten auslesen --> also die gleiche Konstruktion. Nachdem aber nun alle Daten empfangen sind Hängt der Client an Zeile <sockname>.recv(1024) (wegen blocking-Mode)!!
D.h. sowohl Client als auch Server warten darauf, dass der jeweils andere die Verbindung beendet - was aber keiner kann da sie beide im blocking-Mode auf Daten warten. Gibt es eine Möglichkeit dieses Problem zu umgehen? Am besten so etwas wie das komplette Auslesen des Socks bis EOF.
Problem mit vollständigem auslesen der sock-Streams
Ich hab noch nie socks mit python programmiert, würde das dann aber so machen:
Ich weiss nicht ob das geht, aber du kannst es ja mal ausprobieren...
Code: Alles auswählen
ergebnis=''
warte=1
while warte:
a = socken.recv(1)
if a == EOF:
warte=0
ergebnis+=a
mfg,
10011110
10011110
Erst mal Danke für deine Antwort.
Leider hält aber der Python-Interpreter bei
[code]
a=socken.recv(1024)
[/code]
an bis die recive-Methode abgeschlossen wurde. D.h. er kommt gar nicht bis zu der if-Verzweigung :(. Und den Sock in den nonblocking mode zu schalten ist keine Alternative - da kommt teilweise nur Datenmüll raus.
Leider hält aber der Python-Interpreter bei
[code]
a=socken.recv(1024)
[/code]
an bis die recive-Methode abgeschlossen wurde. D.h. er kommt gar nicht bis zu der if-Verzweigung :(. Und den Sock in den nonblocking mode zu schalten ist keine Alternative - da kommt teilweise nur Datenmüll raus.
So ich habe hier mal den Quellcode den ich meine:
Server - funzt eigentlich einwandfrei:
Und hier der Clientcode
Damit es funktioniert muss noch irgendeine Datei namens ftsb.jpg in das gleiche Verzeichnis wie der Script gelegt werden.
Server - funzt eigentlich einwandfrei:
Code: Alles auswählen
"""Ein kleines Beispiel für einen Echoserver in Python."""
autor="Robert Elsner"
version="1.00"
status="alpha 1"
#-------------------------------------------------------------------------------------
from socket import socket, AF_INET, SOCK_STREAM
#Port und Hostname
str_host="localhost"
int_port=8080
#Erstellen des Server-Sockets
sock_server=socket(AF_INET, SOCK_STREAM)
sock_server.bind((str_host, int_port))
sock_server.listen(3)
print "***SERVER ONLINE ON "+str_host+":"+str(int_port)+"***\n"
#-------------------------------------------------------------------------------------
#Die Echoprozedur
def do_echo(sock_client, str_remote_host, int_remote_port):
"""diese Prozedur sendet alle eingehenden Daten zurück an den Empfänger"""
while 1:
try:
str_daten=sock_client.recv(1024)
if not str_daten:break
sock_client.send(str_daten)
print "***DATEN ERFOLGREICH UEBER "+str(sock_client)+" GESENDET***"
except:
sock_client.close()
print "***SOCKET WURDE GESCHLOSSEN: "+str(sock_client)+"***\n"
break
#-------------------------------------------------------------------------------------
#Eventloop damit der Server nach einer Anfrage offen bleibt
while 1:
(sock_client, (str_remote_host, int_remote_port))=sock_server.accept()
print "***EINGEHENDE VERBINDUNG MIT: "+str_remote_host+":"+str(int_remote_port)+"***"
print "***VERBINDUNGSKENNUNG: "+str(sock_client)+"***"
do_echo(sock_client, str_remote_host, int_remote_port)
Code: Alles auswählen
"""Dieses Beispiel soll die Möglichkeiten der
Übertragung von Binärdateien demonstrieren"""
autor="Robert Elsner"
version="1.00"
status="alpha 1"
#-------------------------------------------------------------------------------------
from socket import AF_INET, SOCK_STREAM, socket
#Laden einer Datei
file_handle=open("ftsb.jpg", "rb")
bin_data=file_handle.read()
file_handle.close()
#Herstellen der Verbindung zum Server
sock_client=socket(AF_INET, SOCK_STREAM)
sock_client.connect(("localhost", 8080))
#Senden der Daten
sock_client.send(bin_data)
#Empfangen des Echos
bin_buffer=""
while 1:
bin_data=sock_client.recv(1024)
if not bin_data:break
bin_buffer+=bin_data
print bin_data
print bin_buffer
sock_client.close()
Also OK das mit dem recv(1) funzt (Obwohl ich sicher nachts Alptäume wegen grässlicher Performance bekommen werde). Aber wie sieht ein EOF in einem Sockstream aus?
tja, keine ahnung, aber im zweifelsfall musst du dir eines ausdenken, das im nutzdatenstream nicht vorkomm(t)/(en kann) {
} oder du überlegst dir eine Zeichenkette und testest die z.b:
und dann muss der client nur noch ein 'beep' senden wenn er fertig is und dann sollte das gehen...
Code: Alles auswählen
if bin_buffer[-4:]+bin_data == 'beep':
warte=0
Zuletzt geändert von ASCII158 am Sonntag 2. März 2003, 12:44, insgesamt 1-mal geändert.
mfg,
10011110
10011110
Ja es scheint keine Möglichkeit für ein EOF zu geben. Man muss wohl eintweder eine feste Nachrichtenlänge vereinbaren, einen Delimeter einführen (Deine Idee
), oder einen Streamheader entwerfen.
Ich hatte gehofft es gäbe ein ähnliches Konstrukt wie in TCL wo man einfach read() auf das Socketobjekt anwenden kann und dann sämtliche Daten empfängt. Das wird aber wahrscheinlich ein recht komplexer Code in den darunterliegenden C-Bibliotheken sein.
Deswegen finde ich mich erst mal damit ab und poste ein Feature Request an die Pythonentwickler
.
THX für deine Hilfe.

Ich hatte gehofft es gäbe ein ähnliches Konstrukt wie in TCL wo man einfach read() auf das Socketobjekt anwenden kann und dann sämtliche Daten empfängt. Das wird aber wahrscheinlich ein recht komplexer Code in den darunterliegenden C-Bibliotheken sein.
Deswegen finde ich mich erst mal damit ab und poste ein Feature Request an die Pythonentwickler

THX für deine Hilfe.
Mir fiel wegen der Performance eben noch was ein:
Du lässt den Empfänger erst auf meine Methode mir recv(1) empfangen, und lässt den Sender erst einmal die Länge senden (z.B. '1024\n')
und dann kann der empfänger, da er die länge kennt das ganze mit 1024er und einem <=1024er-Puffer empfangen...
Du lässt den Empfänger erst auf meine Methode mir recv(1) empfangen, und lässt den Sender erst einmal die Länge senden (z.B. '1024\n')
und dann kann der empfänger, da er die länge kennt das ganze mit 1024er und einem <=1024er-Puffer empfangen...
mfg,
10011110
10011110
Mir fiel wegen der Performance eben noch was ein:
Du lässt den Empfänger erst auf meine Methode mir recv(1) empfangen, und lässt den Sender erst einmal die Länge senden (z.B. '1024\n')
und dann kann der empfänger, da er die länge kennt das ganze mit 1024er und einem <=1024er-Puffer empfangen...
Du lässt den Empfänger erst auf meine Methode mir recv(1) empfangen, und lässt den Sender erst einmal die Länge senden (z.B. '1024\n')
und dann kann der empfänger, da er die länge kennt das ganze mit 1024er und einem <=1024er-Puffer empfangen...
mfg,
10011110
10011110
Jo hatte auch gedacht den Header erst separat zu empfangen und auszuwerten. Nur ist das Problem: Das sollte ein kleines Beispiel werden und kein Framework für Netzwerkprogrammierung.
Ach ja ich habe im Moment ein etwas umfangreicheres Projekt am Laufen --> Hast du evtl. lust einzusteigen? Es handelt sich um ein Schulverwaltungssystem auf CGI-Basis (http://www.ftsb.de/asam/). Das Projekt läuft seid ungefähr 7 Monaten (ca 200 Files/10000+ Zeilen code) und es funktionieren schon große Teile (allerdings gibt es noch Unmengen zu tun) - es ist also kein Projekt wo mal alle drei Monate mal eine Zeile Code dazukommt. Ausserdem läuft derzeit ein Betatest bei mir an der Schule.
Ach ja ich habe im Moment ein etwas umfangreicheres Projekt am Laufen --> Hast du evtl. lust einzusteigen? Es handelt sich um ein Schulverwaltungssystem auf CGI-Basis (http://www.ftsb.de/asam/). Das Projekt läuft seid ungefähr 7 Monaten (ca 200 Files/10000+ Zeilen code) und es funktionieren schon große Teile (allerdings gibt es noch Unmengen zu tun) - es ist also kein Projekt wo mal alle drei Monate mal eine Zeile Code dazukommt. Ausserdem läuft derzeit ein Betatest bei mir an der Schule.
lass doch den sender zuerst die länge der gesamten datei senden und der empfänger errechnet dann, wieviele 1024-er recvs er braucht + die länge des letzten recvs. damit hast du das problem umgangen, dass er immer nur kurze stücke sendet!