Wie ein gebrochenes Rohr (SIGPIPE) in Python behandeln?
-
05-07-2019 - |
Frage
Ich habe einen einfachen Multi-Threaded-Game-Server in Python geschrieben, das für jede Client-Verbindung einen neuen Thread erstellt. Ich finde, dass ab und zu, der Server wegen eines gebrochenen Rohr / SIGPIPE Fehler abstürzt. Ich bin mir ziemlich sicher, dass es geschieht, wenn das Programm versucht, eine Antwort zurück an einen Client zu senden, die nicht mehr vorhanden ist.
Was ist ein guter Weg, damit umzugehen? Meine bevorzugte Lösung wäre die serverseitige Verbindung zum Client und bewege auf einfach schließen, anstatt das gesamte Programm zu beenden.
PS: Diese Frage / Antwort befasst sich mit der Problem in allgemeiner Weise; wie gesagt sollte ich es lösen?
Lösung
Lesen Sie oben auf dem Versuch:. Aussage
try:
# do something
except socket.error, e:
# A socket error
except IOError, e:
if e.errno == errno.EPIPE:
# EPIPE error
else:
# Other error
Andere Tipps
Unter der Annahme, dass Sie den Standard-Socket-Modul verwenden, sollten Sie die socket.error: (32, 'Broken pipe')
Ausnahme seinen Fang (nicht IOError wie andere vorgeschlagen haben). Dies wird in dem Fall erhöht werden, die Sie beschrieben haben, das heißt das Senden / Schreiben an eine Steckdose für die die Remote-Seite getrennt wird.
import socket, errno, time
# setup socket to listen for incoming connections
s = socket.socket()
s.bind(('localhost', 1234))
s.listen(1)
remote, address = s.accept()
print "Got connection from: ", address
while 1:
try:
remote.send("message to peer\n")
time.sleep(1)
except socket.error, e:
if isinstance(e.args, tuple):
print "errno is %d" % e[0]
if e[0] == errno.EPIPE:
# remote peer disconnected
print "Detected remote disconnect"
else:
# determine and handle different error
pass
else:
print "socket error ", e
remote.close()
break
except IOError, e:
# Hmmm, Can IOError actually be raised by the socket module?
print "Got IOError: ", e
break
Beachten Sie, dass diese Ausnahme nicht immer auf den ersten Schreibvorgang in einer geschlossenen Buchse angehoben werden - mehr in der Regel die zweite Schreib (es sei denn, die Anzahl von Bytes in dem ersten Schreib geschrieben ist größer als die Puffergröße des Sockets). Sie müssen dies für den Fall im Auge behalten Ihre Anwendung denkt, dass das entfernte Ende die Daten aus dem ersten Schreib empfangen werden, wenn es möglicherweise bereits getrennt.
Sie können die Häufigkeit verringern (aber nicht vollständig beseitigen) dieses durch select.select()
(oder poll
) verwendet wird. Überprüfen Sie, ob Daten bereit, von dem Peer-zu lesen, bevor eine Schreib versuchen. Wenn select
berichtet, dass es verfügbar ist, Daten aus dem Peer-Socket zu lesen, lesen sie socket.recv()
verwenden. Wenn dies eine leere Zeichenfolge zurückgibt, hat die Gegenstelle die Verbindung geschlossen. Da es hier noch eine Race-Bedingung ist, werden Sie noch brauchen, um die Ausnahme zu fangen und zu behandeln.
Verdreht ist für diese Art der Sache, aber es klingt wie Sie bereits ein gutes Stück Code geschrieben hat.
SIGPIPE
(obwohl ich denke, vielleicht meinen Sie EPIPE
?) Auf Sockeln tritt auf, wenn Sie eine Steckdose heruntergefahren und dann Daten versenden. Die einfache Lösung ist nicht die Fassung zu beenden, bevor Sie versuchen, es Daten zu senden. Dies kann auch an Rohren passieren, aber es klingt nicht wie das ist, was Sie erlebt haben, da es sich um ein Netzwerk-Server ist.
Sie kann auch dann nur die Band-Aid, die Ausnahme in einigen Top-Level-Handler in jedem Thread zu fangen.
Natürlich, wenn Sie verwendet Verdrehte anstatt für jede Client-Verbindung einen neuen Thread Laichen, würde nicht Sie wahrscheinlich‘ t haben dieses Problem. Es ist wirklich schwer (vielleicht unmöglich, je nach Anwendung) die Reihenfolge der Nähe zu bekommen und Operationen korrekt schreiben, wenn mehrere Threads mit dem gleichen I / O-Kanal handeln.
Ich stehe mit der gleichen Frage. Aber ich den gleichen Code das nächste Mal einreichen, es funktioniert einfach. Das erste Mal, es brach:
$ packet_write_wait: Connection to 10.. port 22: Broken pipe
Das zweite Mal funktioniert es:
[1] Done nohup python -u add_asc_dec.py > add2.log 2>&1
Ich denke, der Grund, über die aktuelle Server-Umgebung sein kann.
Meine Antwort ist ganz in der Nähe S.Lott ist, außer ich noch insbesondere sein würde:
try:
# do something
except IOError, e:
# ooops, check the attributes of e to see precisely what happened.
if e.errno != 23:
# I don't know how to handle this
raise
, wobei „23“ ist die Fehlernummer, die Sie von EPIPE erhalten. Auf diese Weise werden Sie nicht einen Berechtigungsfehler oder etwas zu behandeln versuchen, sonst sind Sie nicht ausgerüstet.