try - ¿Cómo manejar una tubería rota(SIGPIPE) en python?
tipos de errores en python (5)
Escribí un servidor de juegos simple y multiproceso en python que crea un nuevo hilo para cada conexión de cliente. Me doy cuenta de que de vez en cuando, el servidor se bloquea debido a un error de tubería rota / SIGPIPE. Estoy bastante seguro de que está sucediendo cuando el programa intenta enviar una respuesta a un cliente que ya no está presente.
¿Cuál es una buena manera de lidiar con esto? Mi resolución preferida simplemente cerraría la conexión del lado del servidor con el cliente y continuaría, en lugar de salir de todo el programa.
PD: This pregunta / respuesta trata el problema de una manera genérica; ¿Qué tan específicamente debería resolverlo?
Lea sobre la declaración try:
try:
# do something
except socket.error, e:
# A socket error
except IOError, e:
if e.errno == errno.EPIPE:
# EPIPE error
else:
# Other error
Me enfrento con la misma pregunta. Pero presento el mismo código la próxima vez, simplemente funciona. La primera vez que se rompió:
$ packet_write_wait: Connection to 10.. port 22: Broken pipe
La segunda vez que funciona:
[1] Done nohup python -u add_asc_dec.py > add2.log 2>&1
Supongo que la razón puede ser sobre el entorno actual del servidor.
Mi respuesta es muy similar a la de S.Lott, excepto que sería aún más particular:
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
donde "23" es el número de error que obtienes de EPIPE. De esta forma, no intentará manejar un error de permisos o cualquier otra cosa para la que no esté equipado.
Suponiendo que está utilizando el módulo de socket estándar, debería detectar la socket.error: (32, ''Broken pipe'')
(no IOError como otros han sugerido). Esto se generará en el caso que usted haya descrito, es decir, que envíe / escriba a un socket para el cual el lado remoto se ha desconectado.
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
Tenga en cuenta que esta excepción no siempre se generará en la primera escritura en un socket cerrado, más generalmente en la segunda escritura (a menos que el número de bytes escritos en la primera escritura sea mayor que el tamaño del búfer del socket). Debe tener esto en cuenta en caso de que su aplicación considere que el extremo remoto recibió los datos de la primera escritura cuando ya se haya desconectado.
Puede reducir la incidencia (pero no eliminar completamente) de esto utilizando select.select()
(o poll
). Verifique si hay datos listos para leer del par antes de intentar escribirlos. Si select
informa que hay datos disponibles para leer desde el socket par, socket.recv()
utilizando socket.recv()
. Si esto devuelve una cadena vacía, el par remoto ha cerrado la conexión. Debido a que todavía hay una condición de carrera aquí, igual tendrá que atrapar y manejar la excepción.
Twisted es ideal para este tipo de cosas, sin embargo, parece que ya has escrito un poco de código.
SIGPIPE
(aunque creo que quizás te refieres a EPIPE
?) EPIPE
en los sockets cuando cierras un socket y luego le envías datos. La solución más simple es no cerrar el zócalo antes de intentar enviar datos. Esto también puede ocurrir en las tuberías, pero no parece que eso sea lo que estás experimentando, ya que es un servidor de red.
También puede simplemente aplicar la curita de atrapar la excepción en algún controlador de nivel superior en cada hilo.
Por supuesto, si utilizó Twisted lugar de generar un nuevo hilo para cada conexión de cliente, probablemente no tenga este problema. Es realmente difícil (quizás imposible, dependiendo de su aplicación) hacer que el orden de las operaciones de cierre y escritura sea correcto si varios hilos están tratando con el mismo canal de E / S.