Pregunta

He escrito un servidor de juegos de múltiples subprocesos simple en Python que crea un nuevo subproceso para cada conexión de cliente. Estoy encontrando que de vez en cuando, el servidor se bloqueará debido a un error de pipe-ruptura / 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 servidor al cliente y continuaría, en lugar de salir del programa completo.

PS: Esta pregunta / respuesta trata sobre el problema de una manera genérica; ¿Cómo específicamente debería resolverlo?

¿Fue útil?

Solución

Lee 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

Otros consejos

Suponiendo que está utilizando el módulo de zócalo estándar, debería capturar la excepción socket.error: (32, 'Broken pipe') (no IOError como han sugerido otros). Esto se planteará en el caso que ha descrito, es decir, enviar / escribir 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 producirá en la primera escritura en un socket cerrado, 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 piense que el extremo remoto recibió los datos de la primera escritura cuando ya se haya desconectado.

Puede reducir la incidencia (pero no eliminar por completo) de esto utilizando select.select () (o poll ). Verifique que no haya datos listos para leer del interlocutor antes de intentar una escritura. Si select informa que hay datos disponibles para leer desde el socket del igual, léalos usando socket.recv () . Si esto devuelve una cadena vacía, el interlocutor remoto ha cerrado la conexión. Debido a que todavía hay una condición de carrera aquí, aún deberá capturar 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 tal vez te refieres a EPIPE ?) ocurre en los sockets cuando cierras un socket y luego le envías datos. La solución simple es no apagar el zócalo antes de intentar enviar datos. Esto también puede ocurrir en tuberías, pero no suena como si estuvieras experimentando eso, ya que es un servidor de red.

También puedes aplicar la curita de captura de la excepción en algún controlador de nivel superior en cada subproceso.

Por supuesto, si usas Twisted en lugar de generar un nuevo hilo para cada conexión de cliente, probablemente no t tiene este problema Es realmente difícil (quizás imposible, dependiendo de su aplicación) obtener el orden de las operaciones de cierre y escritura correctas si varios subprocesos tratan con el mismo canal de E / S.

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 el motivo puede ser el entorno del servidor actual.

Mi respuesta es muy parecida 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 recibe de EPIPE. De esta manera, no intentará manejar un error de permisos o cualquier otra cosa para la que no esté equipado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top