python-websockets / websockets

Library for building WebSocket servers and clients in Python

Home Page:https://websockets.readthedocs.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Client state is incorrect

tamir-laminar opened this issue · comments

There is a problem with the client state when sending messaged over a closed socket.

look at the example below:

import asyncio
import websockets

PORT = 22334


async def handle_connection(ws):
    print(f"Got connection request on path: {ws.path}")
    # this code is in comment on propose to see the behaviour of `send` when connection is closed
    # async for message in ws:
    #     print(f"Received message: {message}")
    return


async def main():
    print(f"Starting server on port {PORT}")
    async with websockets.serve(ws_handler=handle_connection, host="localhost", port=PORT):
        print(f"Starting client")
        async with websockets.connect(f"ws://localhost:{PORT}/connect") as client:
            print(f"Sending messages")
            await client.send("Hello, world!")  # expected to fail
            await client.send("Hello, world!")  # expected to fail
            await client.send("Hello, world!")  # expected to fail

            print("Client state is:", client.state.name)  # this should be `CLOSING`, instead we are getting `OPEN`

            try:
                await client.recv()  # this fails correctly because the connection is closed
            except websockets.exceptions.ConnectionClosedOK:
                print("Connection is closed")


if __name__ == "__main__":
    asyncio.run(main())

output:

Starting server on port 22334
Starting client
Got connection request on path: /connect
Sending messages
Client state is: OPEN
Connection is closed

In this example the server gets a connection request from the client and just drop the connection.
The client can still sends messages without getting ConnectionClosedOK exception.

Notes:

  • This behaviour changed in version 11.0, in version 10.4 we would get error in that case.
  • When I'm debugging the code I can see that we are changing the state to CLOSING, but other routine changes the state back to OPEN although it is still close.

This is essentially https://websockets.readthedocs.io/en/stable/faq/asyncio.html#why-does-my-program-never-receive-any-messages

This code doesn't actually yield control to the event loop until await client.recv(). Only then does the event loop get a chance to run and to notice that the connection has been close.

If you add await asyncio.sleep(0.1) right after connect(), you should get the behavior that you expect.