miguelgrinberg / simple-websocket

Simple WebSocket server and client for Python.
MIT License
79 stars 17 forks source link

Sockets left in CLOSE_WAIT state indefinitely when connection is dropped by client #19

Closed innuos-ccarvalho closed 1 year ago

innuos-ccarvalho commented 2 years ago

Hello,

I've noticed that a lot of sockets stay in the CLOSE_WAIT state indefinitely when the connection is dropped by the client. The application is running on Debian and using simple-websocket in a stack with Gunicorn and Flask-SocketIO in threading mode. I would assume that this happens because the server never closes a socket after it's closed by the client or a broken pipe type of error happens.

I've been able to circumvent this behaviour, for testing purposes, by patching simple_websocket.ws.Base._thread() and simple_websocket.ws.Server.close() in run-time. The changes ensure that simple_websocket.ws.Server.close() is always called before simple_websocket.ws.Base._thread() exits and that self.sock.close() is always called on simple_websocket.ws.Server.close().

However I don't fully understand the full implications of this nor if this is the best solution. Furthermore, I thought useful to let you know about this. I'm fully open to get more details if needed, discuss a solution or even do a Pull Request.

miguelgrinberg commented 2 years ago

@innuos-ccarvalho this sounds like an omission on my part, and your description of the solution seems reasonable. Go ahead and submit a PR with your fixes and I'll review it. Thanks!

Elbarto commented 2 years ago

Hi,

I think I came across this bug aswell and here is my input on the subject :

Context : I'm using the flask-sock module to add WebSocket to a flask server, flask-sock is using the simple-websocket module. Thing were working fine except when a client was changing wifi, which cause the WebSocket connection to be dropped from the client without sending the close packet. On the server side, the ping-pong logic is implemented, and my expectation was that a ConnectionError or a ConnectionClosed exception would be raised, but no... Therefore, my code was assuming the WebSocket connection was still alive, and it was trying to send data to it, which cause major break and exception that were not caught...

Expected result : I don't really know what is the protocol to handle a dropped WebSocket connection by the client, but I think it would be great if a ConnectionError or ConnectionClosed is raised when the ping-pong logic fails. (Maybe after a certain amount of failed attempt to avoid a single packet lose to cause the WebSocket termination ?)

Temporary solution : For the moment I've solved the issue by checking if the connected property of the WebSocket is still True before sending it anything. If not, I removed the WebSocket from my active_client list and consider it as terminate. Maybe this is the intended way to go ?

I hope my input will help you finding the best way to solve this issue, Thanks for your great work !