sockets - Cómo cerrar correctamente el socket tanto en el cliente como en el servidor(python)
python-2.7 runtime-error (1)
Estoy escribiendo 2 scripts en python.
- Client.py
- Server.py
Hay un socket entre el cliente y el servidor.
El escenario es este:
Tengo un cliente que pide cerrar el programa, por lo tanto, debería informar al servidor que para entonces informará al otro cliente, por lo tanto, necesito cerrar el socket del cliente (1) al servidor y luego cerrar el socket del servidor a otro cliente (imagínese un juego de 2 personas a las que se les pide que salgan del juego).
Lo estoy haciendo así. En Client.py:
# send the request to the server
eNum, eMsg = Protocol.send_all(self.socket_to_server, msg)
if eNum:
sys.stderr.write(eMsg)
self.close_client()
self.socket_to_server.shutdown(socket.SHUT_WR)
exit(0)
luego en el código de Server.py:
# get the msg from the client that calleds
num, msg = Protocol.recv_all(self.players_sockets[0])
# case of failure
if num == Protocol.NetworkErrorCodes.FAILURE:
sys.stderr.write(msg)
self.shut_down_server()
# case it was disconnected
if num == Protocol.NetworkErrorCodes.DISCONNECTED:
print msg
self.shut_down_server()
technical_win = ("exit" == msg)
# send the msg to the client needed to call
eNum, eMsg = Protocol.send_all(self.players_sockets[1],msg)
if eNum:
sys.stderr.write(eMsg)
self.shut_down_server()
# case end of game (winning or asking to exit)
if technical_win:
self.shut_down_server()
mientras
self.shut_down_server()
es:
def shut_down_server(self):
# close socket of one of the player
self.players_sockets[0].shutdown(socket.SHUT_RDWR)
self.players_sockets[0].close()
# close socket of one of the player
self.players_sockets[1].shutdown(socket.SHUT_RDWR)
self.players_sockets[1].close()
# clean up
exit(0)
Cuando el servidor envía el mensaje que el otro jugador pide para salir del cliente, obténgalo y haciendo lo mismo que mostré al principio.
desafortunadamente no funciona porque cuando el servidor realiza el código:
num, msg = Protocol.recv_all(self.players_sockets[0])
# case of failure
if num == Protocol.NetworkErrorCodes.FAILURE:
sys.stderr.write(msg)
self.shut_down_server()
# case it was disconnected
if num == Protocol.NetworkErrorCodes.DISCONNECTED:
print msg
self.shut_down_server()
entra en el segundo si e imprime
''ERROR - Could not receive a message: timed out.''
¿Cómo soluciono esto correctamente?
PD
Estoy usando Linux
Parece que lo que estás buscando es un cierre elegante. Primero, su código no funciona porque está cerrando el socket inmediatamente después de llamar al apagado.
La regla es que en un cierre correcto, ambos lados deben estar al tanto del cierre y haberlo reconocido antes de que alguien realmente cierre el zócalo. Solo encontré referencia para eso en esta página de MSDN , incluso si se cita en esta otra respuesta SO .
Aquí hay una presentación simplificada de lo que se explica mejor si se hace referencia a la página (no sé cómo formatear correctamente las tablas en SO :-():
-
la parte 1 emite el
shutdown(socket.SHUT_WR)
para notificar que desea finalizar la conexión y continúa leyendo desde el socket -
la parte 2 recibe la indicación de fin de archivo en el socket (lectura vacía) y aún puede enviar cualquier dato restante; luego llama a su vez el
shutdown(socket.SHUT_WR)
- la parte 1 recibe el final del archivo en el socket y sabe que la otra parte ha terminado usando la conexión
- ambas partes pueden cerrar el zócalo
Observación: no importa si la parte 2 realmente cierra el socket antes de que la parte 1 recibiera el final del archivo, porque la parte 1 ya solo estaba esperando una indicación de finalización: no se pueden perder datos