Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issues listening incoming messages in websocket client on Python 3.6

I'm trying to build a websocket client on Python using websockets package from here: Websockets 4.0 API

I'm using this way instead of example code because I want to create a websocket client class object, and use it as gateway.

I'm having issues with my listener method (receiveMessage) on client side, which raises a ConnectionClose exception at execution. I think maybe there is any problem with the loop.

This is the simple webSocket client I've tried to build:

import websockets

class WebSocketClient():

    def __init__(self):
        pass

    async def connect(self):
        '''
            Connecting to webSocket server

            websockets.client.connect returns a WebSocketClientProtocol, which is used to send and receive messages
        '''
        self.connection = await websockets.client.connect('ws://127.0.0.1:8765')
        if self.connection.open:
            print('Connection stablished. Client correcly connected')
            # Send greeting
            await self.sendMessage('Hey server, this is webSocket client')
            # Enable listener
            await self.receiveMessage()


    async def sendMessage(self, message):
        '''
            Sending message to webSocket server
        '''
        await self.connection.send(message)

    async def receiveMessage(self):
        '''
            Receiving all server messages and handling them
        '''
        while True:
            message = await self.connection.recv()
            print('Received message from server: ' + str(message))

And this is the main:

'''
    Main file
'''

import asyncio
from webSocketClient import WebSocketClient

if __name__ == '__main__':
    # Creating client object
    client = WebSocketClient()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(client.connect())
    loop.run_forever()
    loop.close()

To test incoming messages listener, server sends two messages to client when it stablishes the connection.

Client connects correctly to server, and sends the greeting. However, when client receives both messages, it raises a ConnectionClosed exception with code 1000 (no reason).

If I remove the loop in the receiveMessage client method, client does not raise any exception, but it only receives one message, so I suppose I need a loop to keep listener alive, but I don't know exactly where or how.

Any solution?

Thanks in advance.

EDIT: I realize that client closes connection (and breaks loop) when it receives all pending messages from server. However, I want client keeps alive listening future messages.

In addition, I've tried to add another function whose task is to send a 'heartbeat' to server, but client closes connection anyway.

like image 615
CharlieHollow Avatar asked Apr 17 '18 13:04

CharlieHollow


People also ask

Is Python good for WebSockets?

The communication can be sent either way at any time during the lifetime of the WebSocket connection. The client and the server are continuously connected — data can be sent to the clients all the time, without any need to request it. It's fairly easy to work with WebSockets in Python.

What is the best WebSocket library for Python?

Our recommended Python WebSocket library is the websocket-client library. The library is compatible with both Python 2 and Python 3, but for new code we recommended only using Python 3 as Python 2 is in the process of being deprecated.

How do I receive WebSocket data?

First, you need to copy your web browser's header to here and use json. dumps to convert it into the string format. After that, create the connection to the server by using create_connection . Then, perform the handshake by sending the message, and you will be able to see the data on your side.

How do I use WebSockets client in Python?

WebSocket Client with PythonCreate a new File “client.py” and import the packages as we did in our server code. Now let's create a Python asynchronous function (also called coroutine). async def test(): We will use the connect function from the WebSockets module to build a WebSocket client connection.


1 Answers

Finally, based on this post answer, I modified my client and main files this way:

WebSocket Client:

import websockets
import asyncio

class WebSocketClient():

    def __init__(self):
        pass

    async def connect(self):
        '''
            Connecting to webSocket server

            websockets.client.connect returns a WebSocketClientProtocol, which is used to send and receive messages
        '''
        self.connection = await websockets.client.connect('ws://127.0.0.1:8765')
        if self.connection.open:
            print('Connection stablished. Client correcly connected')
            # Send greeting
            await self.sendMessage('Hey server, this is webSocket client')
            return self.connection


    async def sendMessage(self, message):
        '''
            Sending message to webSocket server
        '''
        await self.connection.send(message)

    async def receiveMessage(self, connection):
        '''
            Receiving all server messages and handling them
        '''
        while True:
            try:
                message = await connection.recv()
                print('Received message from server: ' + str(message))
            except websockets.exceptions.ConnectionClosed:
                print('Connection with server closed')
                break

    async def heartbeat(self, connection):
        '''
        Sending heartbeat to server every 5 seconds
        Ping - pong messages to verify connection is alive
        '''
        while True:
            try:
                await connection.send('ping')
                await asyncio.sleep(5)
            except websockets.exceptions.ConnectionClosed:
                print('Connection with server closed')
                break

Main:

import asyncio
from webSocketClient import WebSocketClient

if __name__ == '__main__':
    # Creating client object
    client = WebSocketClient()
    loop = asyncio.get_event_loop()
    # Start connection and get client connection protocol
    connection = loop.run_until_complete(client.connect())
    # Start listener and heartbeat 
    tasks = [
        asyncio.ensure_future(client.heartbeat(connection)),
        asyncio.ensure_future(client.receiveMessage(connection)),
    ]

    loop.run_until_complete(asyncio.wait(tasks))

Now, client keeps alive listening all messages from server and sending 'ping' messages every 5 seconds to server.

like image 157
CharlieHollow Avatar answered Oct 19 '22 06:10

CharlieHollow