Socket brocken pipe

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
dannyboy385
User
Beiträge: 39
Registriert: Freitag 27. November 2015, 21:24

Hallo community. Dar ich nun immer noch ein anfänger bin habe ich versucht einen einfachen socketserver und client zu schrteiben welcher einen eingegebenen text an den server sendet und dieser jenen zurück sendet. Leider bekomme ich beim 2ten sendeversuch keine antwort mehr und beim 3ten bekomme ich den Fehler Brocken Pipe Error : Errno32

das Clientprogramm

Code: Alles auswählen

'''daten dan socket senden'''

#socket erstellen

import os
import socket
import sys


hostip="192.168.1.101"
port=9000

s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.connect((hostip,port))

while 1:
	data = input("Test eingeben")
	s1.send (data.encode('utf-8'))
	backdata=s1.recv(1024)
	print (backdata)


Serverprogramm

Code: Alles auswählen

#!/usr/bin/env python3

import os
import socket

hostip="192.168.1.101"
port=9000
backlog=5
size=1024

socket1=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket1.bind ((hostip,port))
socket1.listen(backlog)
print("socket set up and running")
client.adress = socket1.accept()
while (True):
	data=client.recv(size)
	print (data)
	answer= input ("Antwort:    ")
	data=data+answer
	if data:
		client.send (data)

der code wird euch warscheinlich erschrecken. Der erfolg der ersten gelungenen übertragung hat sich leider beim 2ten versuch schon in Rauch aufgelöst. Ich hoffe ihr könnt mir helfen.
Zuletzt geändert von Anonymous am Dienstag 22. Dezember 2015, 13:45, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@dannyboy385: ich bekomme einen NameError, weil client in 'client.adress' nicht definiert wird. Außerdem ist data vom Typ bytes und answer vom Typ str, was man nicht zusammenstückeln kann. Was meinst Du mit 2tem Sendeversuch? Ein zweiter Client? Der kann nicht sich nicht mehr verbinden, weil der Server nach dem ersten Client auf keine weiteren mehr wartet.
dannyboy385
User
Beiträge: 39
Registriert: Freitag 27. November 2015, 21:24

Also einen Name error bekomme ich nicht. Das mit binarie und str lief folgendermaßen ab. Das ganze als normalen str ohne coding zu senden war nicht möglich da bekahm ich einen Fehler welchen ich nun nicht mehr im kopf habe. Also fügte ich das Coding hinzu. Nun kahm das Paket am Server an und wurde auch zurückgesendet. Das Allerdings als binary. obwohl der Typ am Server nicht geändert wurde.
Da war das Motto. Hauptsache es läuft. Wobei ich auch nicht verstehe warum die printfunktion Serverseitig nicht funktioniert obwohl Data bereits empfangen wurde. Mit 2tem Sendeversuch meine ich das wenn ich nun eine Eingabe sende, kommt diese Am Server an und wird richtig zurückgesendet. Wenn ich jetzt noch eine Eingabe Sende kommt diese am Server scheinbar an aber der Server gibt ein leeres Paket zurück.
Beim 3ten Sendeversuch einer neuen Eingabe kommt nun der Socket Error brocken pipe. Das Verstehe ich nicht ganz. Wäre sehr net wenn mir einer Helfen könnte. Ich bin ratlos. Zumal mir nicht klar ist wie ich Clientseitig den Socket des Servers schließen könnte wenn alle nötigen Daten übertragen wurden.

Die ist nun nur ein kleiner Testlauf.
Ziel des ganzen ist zu versuchen Dateien mit einem Editor einzulesen. Diese in 1024Byte Packete zu teilen, an den Server zu senden und wieder zusammenzusetzen. Also eine Kopie einer beliebigen Datei über einen Netzwerksocket.
Natürlich gibt es das schon. Aber das Probieren ist mir genau so wichtig wie eventuelle syntax und schönheitfehler in künftigen programmen zu vermeiden.
Meiner Meinung nach ist der Lern effekt doch größer wenn man etwas ausprobiert, anstatt es aus irgendeinem Buch abzutippen und zu sehen ja es geht....aber warum weis ich nicht.

Auch wären hinweise auf eventuelle verkürzungmöglichkeiten des Codes interessant.

PS: könnte mich eventuell einer Aufklären welche funktion % in einem Python script übernehmen und ob die verwendung jener sinnvoll ist.

MFG und noch einen schönen Abend
Daniel
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@dannyboy385: solange Du hier nicht den Code zeigst, den Du tatsächlich verwendest, macht es aus meiner Sicht wenig Sinn zu spekulieren, warum bei Dir etwas nicht funktioniert.
BlackJack

@dannyboy385: Nur um Missverständnissen vorzubeugen weil Du mehrfach von Paketen sprichst: TCP ist ein Datenstrom und kennt erst einmal keine Datenpakete. Wenn Du in diesem Datenstrom mehrere ”Pakete” voneinander unterscheiden können willst, dann must *Du* das im Programm eine entsprechende Struktur in die Daten bringen und beim versenden und empfangen selber dafür sorgen das die Grenzen dieser Pakete erkannt und berücksichtigt werden. Wenn du auf der einen Seite mehrfach 1024 Bytes in den Datenstrom steckst, dann heisst das nicht das die auch in solchen 1024 Byte Häppchen auf der anderen Seite ankommen. Da können pro Aufruf mehr oder weniger Daten abgerufen werden, die Grössenangabe bei `recv()` ist nur eine Obergrenze. Da kann im Extremfall auch bei jedem Aufruf nur ein Byte geliefert werden so dass man für 1024 Bytes an Daten die mit einem `sendall()` auf die Reise geschickt wurden 1024 mal ``sock.recv(1024)`` aufrufen muss und jedes mal nur ein Byte bekommt. Auch wenn dieser Extremfall unwahrscheinlich ist, so muss robuster Socket-Code auch mit so einer Situation umgehen können.

An der Stelle versagen leider auch viele Bücher oder Socket-Beispiel-Code von Leuten die nur mal schnell Sockets zeigen wollen, aber von dem Thema nicht so viel Ahnung haben. Man findet leider viele schlechte, weil kaputte, Beispiele. Nicht nur im Netz, sondern auch in so einigen Büchern.

Noch ein Tipp um Fehlermeldungen zu zeigen: Schreib die nicht ab sondern kopiere sie, denn wenn Dein System tatsächlich „brocken pipe“ meldet, dann ist es wohl ziemlich „brocken“, äh pardon, *broken*. ;-)

Was die Programme angeht: Du bist in beiden Beispielen inkonsequent was Schreibweisen angeht, als wenn Du aus zwei verschiedenen Quellen kopiert hättest. Grundsätzlich kann ein Blick in den Style Guide for Python Code nicht schaden. Namen sollte man nicht durchnummerieren was bei `s1` gar keinen Sinn macht und bei `socket1` nur in sofern als das man sich damit den Namen des Moduls nicht verdeckt. Da verwenden die meisten Module allerdings den Namen `sock` als Ausweg. Ist zwar nicht wirklich schön, aber üblich.

Der Kommentar im Client steht so überhaupt nicht in der Nähe der Codezeile die dann tatsächlich das macht was im Kommentar steht. Würde er dort stehen, wäre er überflüssig, denn das sieht man ja schon am Code selber. Kommentare beschreiben üblicherweise nicht *was* Code macht, denn dafür hat man ja schon den Code, sondern *warum* er das so macht wie er es macht. Und das auch nur wenn das nicht offensichtlich ist. Wobei man dabei durchaus von einem halbwegs kompetenten Programmierer ausgehen sollte bei der Entscheidung was offensichtlich ist und nicht von einem absoluten Anfänger.

Python hat spezielle Wahrheitswerte (`True` und `False`) die man auch verwenden sollte anstatt von Zahlen.

Die Client hat das besagte Datenstrom-Problem. Das `recv()` muss nicht alle Daten liefern die der Server gesendet hat. Es kann sein dass man das mehrfach aufrufen muss. Gleiches gilt für den Server.

Die Bedingungen bei ``while`` & Co gehören nicht in überflüssige Klammern gesetzt.

Für das beschriebene Dateiübertragungsproblem würde ich von den Sockets Dateiobjekte abfragen — die haben da eine Methode für — und dann die passenden Funktionen aus dem `shutil`-Modul für das Kopieren verwenden. Wenn da mehr als eine Datei über eine Verbindung gehen soll, zum Beispiel vorher der Dateinamen, dann müsstest Du Dir ein Protokoll ausdenken und implementieren. Oder das mit den Low-Level-Sockets sein lassen und etwas existierendes verwenden.

``%`` ist ein binärer Operator dessen Bedeutung wie bei allen Operatoren von den beteiligten Datentypen der Operanden abhängt. Bei Zahlen ist es beispielsweise die Modulo-Operation, die sinnvoll ist, wenn sie sinnvoll ist. Und bei Zeichenketten die mittlerweile etwas veraltete Zeichenkettenformatierung, die durch die `format()`-Methode abgelöst wurde. Beides hätte man in der Python-Dokumentation nachlesen können. Das Tutorial dort und die Referenz zu den grundlegenden Typen sollte man irgendwann einmal durchgearbeitet haben. Um die Grundlagen kommt man nicht herum.
dannyboy385
User
Beiträge: 39
Registriert: Freitag 27. November 2015, 21:24

@Sirius3
Der Code steht im Ausgangspost

@BlackJack
"die Grössenangabe bei `recv()` ist nur eine Obergrenze"
Damit wäre zumindest ein missverständniss beseitigt. Danke

Die genaue Meldung lautet:
Traceback (most recent call last):
File "socket2.py", line 18, in <module>
s1.send (data.encode('utf-8'))
BrokenPipeError: [Errno 32] Broken pipe


"Was die Programme angeht: Du bist in beiden Beispielen inkonsequent was Schreibweisen angeht, als wenn Du aus zwei verschiedenen Quellen kopiert hättest. Grundsätzlich kann ein Blick in den Style Guide for Python Code nicht schaden. Namen sollte man nicht durchnummerieren was bei `s1` gar keinen Sinn macht und bei `socket1` nur in sofern als das man sich damit den Namen des Moduls nicht verdeckt. Da verwenden die meisten Module allerdings den Namen `sock` als Ausweg. Ist zwar nicht wirklich schön, aber üblich."

Das ist wohl war. Nein kopiert ist davon nichts. Mehr oder weniger ist der Code in der Art entstanden das ich mir :
https://docs.python.org/3.4/library/soc ... et-objects

zur hand genommen habe und mehr oder weniger erst einmal versuchen wollte überhaupt eine Verbindung aufzubauen.
Die Namens gebung ist wohl wirklich eine mittlere Katastrophe...

Wenn recv nicht alle Daten liefern muss die der Server gesendet hat, müsste das umgekehrt ja auch der Fall sein, sehe ich das richtig?
Im nächsten gedankengang komme ich dann an den Punkt...TCP ist ein stream...also wenn der Server nun 10 einzelne Nachrichten an den Server senden würde...wäre es dann möglich das sich das ganze in ein einziges Datenkaos zerlegt. Sprich der client sendet als primitives Beispiel 10mal Hallo in UTF8 ...und am Server kommen nach 6 recv 6mal kauderwelsch an.

Zur Modulo Funktion:
Gelesen habe ich davon. Verstanden habe ich es leider nicht.



mfg danny
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

dannyboy385 hat geschrieben:Zur Modulo Funktion:
Gelesen habe ich davon. Verstanden habe ich es leider nicht.
modulo == Divisionsrest. Wenn du eine Uhr mit Zeigern lesen kannst, kannst du modulo rechnen. Wieviel Uhr ist 21:00 Uhr plus fünf Stunden? 26:00 Uhr?
In specifications, Murphy's Law supersedes Ohm's.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@dannyboy385: ich dachte, Du hast tatsächlich die gesamten Fehlermeldungen gepostet. Dann mach ich das halt für Dich:

Code: Alles auswählen

Traceback (most recent call last):
  File "server.py", line 15, in <module>
    client.adress = socket1.accept()
NameError: name 'client' is not defined
Bei einem Stream kommt am anderen Ende kein Kauderwelsch an, sondern die Bytes in der Reihenfolge wie sie gesendet wurden. Wenn Du 10mal Hallo sendest, kommt eben nach 6 recv irgendetwas zwischen HalloH und HalloHalloHalloHalloHalloHalloHalloHalloHalloHallo an.
BlackJack

@dannyboy385: Der Code im Ausgangsbeitrag führt beim Server zu dem `NameError` den Sirius3 beschrieben hat. Also muss der mindestens in der Zeile anders aussehen wenn Du den ohne diesen Fehler laufen lassen kannst.

Selbst wenn die Zeile richtig wäre, würde man bei dem gezeigten Quelltext in einen `TypeError` laufen wenn versucht wird die empfangenen Bytes mit der eingegebenen Zeichenkette zu verbinden. Der Server würde so wie er dort steht also niemals eine Antwort an den Client senden sondern sich mit einer Fehlermeldung beenden. Was dann beim Client beim `recv()` zum „broken pipe“ führen kann, weil die Gegenseite plötzlich weg ist wenn der Server sich wegen dem Fehler dort beendet.

`send()` muss nicht alle Daten senden. Die Methode liefert die Anzahl der Bytes zurück die tatsächlich an das Socket zum senden übergeben wurden. Man muss die Methode als so oft mit den jeweiligen Restdaten aufrufen bis alles raus ist. Oder `sendall()` verwenden, was das netterweise für einen macht. Oder sich ein Dateiobjekt von dem Socket geben lassen was `read()` und `write()` so implementiert wie man das von Dateiobjekten in Python gewohnt ist und was auch iterierbar ist und dann die Zeilen liefert die empfangen wurden. So kann man sich zeilenbasierte Protokolle ohne die Umstände mit `recv()` implementieren.

Ob man das jetzt als Datenchaos bezeichnen kann — das ist vielleicht etwas übertrieben. Die Daten kommen schon in der Reihenfolge an wie man sie abgeschickt hat. Wenn mehr als nur einen gleichförmigen Datenstrom senden will, dann muss man halt dafür sorgen dass man den Datenstrom in die Teile/Pakete/Nachrichten aufteilt die man abgesendet hat. Dafür muss man sich geeignete Massnahmen ausdenken und umsetzen um Nachrichten voneinander trennen zu können. Zum Beispiel in dem alle Nachrichten eine feste grösse haben. Oder ein Byte oder eine Bytefolge die garantiert nicht innerhalb einer Nachricht vorkommen kann als Endmarkierung. Oder man schickt ganz am Anfang einer Nachricht immer die Information wie lang die Nachricht ist. Die Längenangabe selbst mit einer festen Länge oder durch eine Endmarkierung vom Rest der Nachricht getrennt. Das sind so die üblichen Varianten. Man kann die auch kombinieren. Und das Ende der Daten kann man auch durch den Abbruch der Senderichtung vom Sender aus signalisieren wenn es okay ist das der Sender über diese Verbindung danach nichts mehr senden kann und für eine neue Kommunikation eine neue TCP-Verbindung aufgebaut werden muss.
Antworten