IIC2233 / syllabus-2019-1

Repositorio oficial del curso IIC2233 Programación Avanzada 🎉 🎊
43 stars 69 forks source link

ConnectionResetError #628

Closed cmarquez1 closed 5 years ago

cmarquez1 commented 5 years ago

Hola, me sale este error "ConnectionResetError: [WinError 10054] Se ha forzado la interrupción de una conexión existente por el host remoto" cuando cierro un cliente y no se si trato de enviarle algo al socket del cliente que cerre y el cual elimine del dict de sockets que tengo, no tengo mucha idea de como solucionarlo.

gatochico commented 5 years ago

Hola! ~Probablemente se debe a que no esperas a que el server saque el socket del cliente respectivo antes de cerrarlo. Se debe primero sacar el socket de la lista y una vez realizado esto, se debe permitir cerrar la ventana del cliente.~

~Revisé rapidamente tu código y hay una función en la parte que sacaste de las ayudantias en el archivo client/main.py llamada terminar_conexion(self) que posee los pasos correctos para cerrar un socket de un cliente :eyes: Como ya esta implementada, te falta identificar en que otras partes de tu código requieres cerrar la conexión (ej: se cierra ventana, ya sea por un boton implementado por ti o mediante la X de la ventana) y hacer el llamado a dicha función.~ Ver última respuesta, donde está todo mejor explicado y probado en código.

Cualquier duda comenta y saludos!

cmarquez1 commented 5 years ago

Por lo tanto, primero elimino el socket del diccionario del server y despues hago que el cliente termine la conexion con la funcion terminar_conexion(self)

gatochico commented 5 years ago

Algo así! Ahora fijandome mejor, la funcion terminar conexion solo se encarga del lado del cliente, asi que debes tu implementar el envio del aviso al server. Si quieres, puedes hacer una nueva funcion que haga todos los pasos por ti, que serían el primero mandar un mensaje al server para que elimine el socket, y luego haga el procedimiento para cerrar todo en el lado del cliente (Que seria cerrar el socket del lado del cliente y cerrar cualquier interfaz que se haya abierto). No importa como lo hagas, pero debe ser en ese orden (Server - cliente) para que no te salga el error.

cmarquez1 commented 5 years ago

Lo que trato de hacer es
"del self.sockets[client_socket] msj = {"status": "chao"} self.send(msj, client_socket)" desde el servidor, que elimina el socket del cliente del diccionario de sockets del servidor, y le envia un send al cliente para que el en cliente cuando el status es "chao" este utilize la funcion terminar_conexion(self). Sin embargo, me sigue apareciendo el error

cmarquez1 commented 5 years ago

Acabo de subir mi código por cualquier cosa

gatochico commented 5 years ago

Siento la demora, estaba leyendo tu código y quería darte la respuesta más completa posible!

El problema persiste ya debido en específico a las siguientes dos líneas en el manejo del comando "cerrar_sesion" en el server:

msj = {"status": "chao"}
self.send(msj, client_socket)

Ya que quieres mandar un mensaje al cliente, pero este ya se desconectó. Hay dos formas de arreglarlo, dependiendo si implementarás el bonus de servidor y cliente robusto o no. 1) Si no deseas implementar dicho bonus, simplemente borra ambas líneas que especifiqué anteriormente. El cliente se cerrará, y el server ya habrá recibido la info. necesaria para sacar su socket de la lista de sockets así que no es necesario hacer nada más. 2) Si deseas implementar el bonus, deberías reemplazar ambas líneas por una verificación que vea si el usuario estaba en una partida o chat y mandar el mensaje correspondiente ('usuario x se desconectó') a todos los otros sockets que compartían sala con este (Preocupandote de no mandarle el mensaje al socket que se desconectó, o de nuevo te lanzará el error).

Pensandolo mejor, el hacer el manejo de cerrar todo bien en el lado del cliente no es 100% necesario, aunque sería una buena práctica (pero no afectará tu nota). Si quieres cerrar todo más 'formalmente', podrías definir el closeEvent de pyqt5 para primero, mande un mensaje al server con el comando "cerrar_sesion" e inmediatamente ejecute la funcion terminar_conexion(self) (sin esperar que el server le diga que ejecute, ya que recuerda que no podrá enviarle más mensajes como dije antes). Recalco, esto no es necesario, y haciendo sólo los 1 de los 2 pasos mencionados arriba se debería solucionar el problema.

Saludos!

cmarquez1 commented 5 years ago

Y si despues de eliminar el socket del diccionario ocupo hago socket.close() del socket del cliente que quiero cerrar la ventana?

gatochico commented 5 years ago

Podrías especificar más tu pregunta? Quieres cerrar el socket en el archivo main del cliente?

cmarquez1 commented 5 years ago

En el main del servidor

gatochico commented 5 years ago

No sería necesario hacer socket.close(), ya que el cliente ya cerró su programa/ventana en ese punto.

cmarquez1 commented 5 years ago

gracias!