KE Keronei
KE Keronei

Reputation: 330

How should I correctly configure tasks when using sockets in python?

I have this small snippet which I intend to have function as a server, I have managed to get the socket to connect to the client but cannot send data due to errors.

import asyncio
import json
import socketio
from aiohttp import web

ALLOWED_ORIGINS = ["http://localhost:45100"]

sio = socketio.AsyncServer(cors_allowed_origins=ALLOWED_ORIGINS)
app = web.Application()#socketio.ASGIApp(sio)
sio.attach(app)

@sio.event
async def connect(sid, environ):
    origin=environ.get('HTTP_ORIGIN', '')
    if origin not in ALLOWED_ORIGINS:
        print(f'Connection from {origin} imetupwa')
        await sio.disconnect(sid)

    else:
        print(f'Allowing connection from {origin}')

@sio.event
async def disconnect(sid):
    print('Disconnected', sid)

async def send_gpio_data():
    print('Going to send data')
    try:
        while True:
            data = {'speed': 100}
            await sio.emit('ecuData', json.dumps(data))
            print("Data sent, sleeping...")
            await asyncio.sleep(1)
    except Exception as error:
        print(f'Error in sending data: {error}')

async def main():
    print('Init main')
    asyncio.create_task(send_gpio_data())

    runner = web.AppRunner(app)
    await runner.setup()
    site = web.TCPSite(runner, '0.0.0.0', 8090)
    print("Web app running on http://0.0.0.0:8090")
    await site.start()

    await asyncio.Event().wait()


if __name__ == '__main__':
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("Done!")

Here is the putout:

Init main
Web app running on http://0.0.0.0:8090
Going to send data
Data sent, sleeping...
Allowing connection from http://localhost:45100
Error in sending data: Passing coroutines is forbidden, use tasks explicitly.
/Users/keronei/StudioProjects/Side Projects/rotor/server.py:35: RuntimeWarning: coroutine 'AsyncServer._emit_internal' was never awaited
  print(f'Error in sending data: {error}')
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

The execution stops right after the crash, I have also tried sio.start_background_task(send_gpio_data) but I get the same error.

Upvotes: 1

Views: 102

Answers (2)

KE Keronei
KE Keronei

Reputation: 330

I found the problem to be an incompatible asyncio with Python version.

On a random search, someone responded to the same issue on Medium with the following comment, I presume the commenter is a maintainer/contributor:

...but for this error, I suspect that it's because the Python version I've used for the template was below 3.11. For me, I used 3.10. Could you downgrade the Python version (by creating another virtualenv) and try it out with a different version?

From this, I re-created the virtual environment with Python 3.9 and the error went away.

This is just a fix, but there should be a correct approach for Python 3.10 and up.

If curious, here is what I did (on Mac):

  1. Checked the versions of Python that are installed
which -a python python3

This returns a list of installation locations, I picked each of them (to figure out if there was 3.10 or below)

$ /usr/local/bin/python3

This opens a Python environment with the version indicated.

  1. I deleted and created a new virtual environment:
virtualenv  -p /usr/bin/python3 env 

I then activated and ran the script and the error was gone.

Upvotes: 0

user23476310
user23476310

Reputation: 1

import asyncio
import json
import socketio
from aiohttp import web

ALLOWED_ORIGINS = ["http://localhost:45100"]

sio = socketio.AsyncServer(cors_allowed_origins=ALLOWED_ORIGINS)
app = web.Application()
sio.attach(app)

@sio.event
async def connect(sid, environ):
    origin = environ.get('HTTP_ORIGIN', '')
    if origin not in ALLOWED_ORIGINS:
        print(f'Connection from {origin} rejected')
        await sio.disconnect(sid)
    else:
        print(f'Allowing connection from {origin}')

@sio.event
async def disconnect(sid):
    print('Disconnected', sid)

async def send_gpio_data():
    print('Going to send data')
    try:
        while True:
            data = {'speed': 100}
            await sio.emit('ecuData', data)  # No need to json.dumps, just send dict
            print("Data sent, sleeping...")
            await asyncio.sleep(1)
    except Exception as error:
        print(f'Error in sending data: {error}')

async def main():
    print('Init main')
    # Schedule the coroutine to run in the background
    sio.start_background_task(send_gpio_data)

    runner = web.AppRunner(app)
    await runner.setup()
    site = web.TCPSite(runner, '0.0.0.0', 8090)
    print("Web app running on http://0.0.0.0:8090")
    await site.start()

    await asyncio.Event().wait()

if __name__ == '__main__':
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("Done!")

Upvotes: -1

Related Questions