17
votes

I'm having the same problem as this github issue with python websockets: https://github.com/aaugustin/websockets/issues/367

The proposed solution isn't working for me though. The error I'm getting is:

websockets.exceptions.ConnectionClosed: WebSocket connection is closed: code = 1006 (connection closed abnormally [internal]), no reason

This is my code:

async def get_order_book(symbol):
    with open('test.csv', 'a+') as csvfile:
        csvw = csv.writer(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL)
        DT = Data(data=data, last_OB_id=ob_id, last_TR_id=tr_id, sz=10, csvw=csvw)

        while True:
            if not websocket.open:
                print('Reconnecting')
                websocket = await websockets.connect(ws_url)
            else:
                resp = await websocket.recv()
                update = ujson.loads(resp)
                DT.update_data(update)

async def get_order_books():
    r = requests.get(url='https://api.binance.com/api/v1/ticker/24hr')
    await asyncio.gather(*[get_order_book(data['symbol']) for data in r.json()])

if __name__ == '__main__':
    asyncio.run(get_order_books())

The way I've been testing it is by closing my internet connection, but after a ten second delay it still returns the 1006 error.

I'm running Python 3.7 and Websockets 7.0.

Let me know what your thoughts are, thanks!

6

6 Answers

27
votes

I encountered the same problem. After digging a while I found multiple versions of the answer that tells to just reconnect, but I didn't think it was a reasonable route, so I dug some more.

Enabling DEBUG level logging I found out that python websockets default to sending ping packets, and failing to receive a response, timeouts the connection. I am not sure if this lines up with the standard, but at least javascript websockets are completely fine with the server my python script times out with.

The fix is simple: add another kw argument to connect:

websockets.connect(uri, ping_interval=None)

The same argument should also work for server side function serve.

More info at https://websockets.readthedocs.io/en/stable/api.html

3
votes

So I found the solution:

When the connection closes, it breaks out of the while loop for some reason. So in order to keep the websocket running you have to surround

resp = await websocket.recv()

with try ... except and have

print('Reconnecting')
websocket = await websockets.connect(ws_url)

in the exception handling part.

2
votes

I might be a year late but i was just having this issue. No connection issues on my html5 websocket client but .py test client would crash after around a minute (raising 1006 exceptions for both the client and server too). As a test i started to just await connection.recv()ing after every frame the client sends. No more issues. I didnt need to receive data for my .py test client but apparently it causes issues if you let it build up. It's also probably why my web version was working fine, since i was handling the .onmessage callbacks.

Im pretty sure this is why this error occurs. So this solution of just receiving the data is an actual solution and not disabling pinging and screwing up a vital function of the protocol.

1
votes

I ran in to this same issue. The solution by shinola worked for awhile, but I would still get errors sometimes.

To handle this I put the connection into a while True: loop and added two separate try except blocks. The consumer variable is a function that processes the messages received from the websocket connection.

async def websocketConnect(uri, payload, consumer):
    websocket = await websockets.connect(uri, ssl=True)
    await websocket.send(json.dumps(payload))
    while True:
        if not websocket.open:
            try:
                print('Websocket is NOT connected. Reconnecting...')
                websocket = await websockets.connect(uri, ssl=True)
                await websocket.send(json.dumps(payload))
            except:
                print('Unable to reconnect, trying again.')
        try:
            async for message in websocket:
                if message is not None:
                    consumer(json.loads(message))
        except:
            print('Error receiving message from websocket.')

I start the connection using:

def startWebsocket(uri, payload, consumer):
    asyncio.run(websocketConnect(uri, payload, consumer))
0
votes

I think they explained here: https://websockets.readthedocs.io/en/stable/faq.html

it means that the TCP connection was lost. As a consequence, the WebSocket connection was closed without receiving a close frame, which is abnormal.

You can catch and handle ConnectionClosed to prevent it from being logged.

There are several reasons why long-lived connections may be lost:

End-user devices tend to lose network connectivity often and unpredictably because they can move out of wireless network coverage, get unplugged from a wired network, enter airplane mode, be put to sleep, etc.

HTTP load balancers or proxies that aren’t configured for long-lived connections may terminate connections after a short amount of time, usually 30 seconds.

-1
votes

I solved this problem by uvicorn the table with a hypercorn.

hypercorn app:app