asyncio, server does not call handle_client

The official PYBD running MicroPython, and its accessories.
Target audience: Users with a PYBD
Post Reply
arg
Posts: 6
Joined: Wed Jul 06, 2022 8:50 am

asyncio, server does not call handle_client

Post by arg » Sat Jul 09, 2022 1:24 pm

Hello :)
It is likely that I am a dummy.

Pyboard series D
MicroPython v1.19.1 on 2022-06-18; PYBD-SF2W with STM32F722IEK
uasyncio version 3
wifi seems to work as expected

When a simple string is sent by another application to the server ( DGRAM) :
- no faults are displayed in the terminal window for the pyboard
- the sending application shows no faults
- so there is no useful action, the print statement is not executed

It is as though the handle_client does nothing.

Several other simple test tasks run as expected.

Snippet -------------------------------------------------------------------------------------------------------------------

Code: Select all

# https://stackoverflow.com/questions/48506460/python-simple-socket-client-server-using-asyncio    
async def handle_client(reader:StreamReader,writer :StreamWriter):

  print('in handle_client')

  request = None
  while request != 'quit':
      request = (await reader.read(2)).decode('utf8')
      print(request)
      response = str(eval(request)) + '\n'
      writer.write(response.encode('utf8'))
      await writer.drain()
  await writer.close()

# --------------------------------------------------
async def run_server():
    
    server = await asyncio.start_server(handle_client,local_IP,local_port)
    
    async with server: await server.serve_forever()
        
#----------------------------------------------------------------------------------
async def main():

  asyncio.create_task(task1())
  asyncio.create_task(task2())
  asyncio.create_task(task3())
  asyncio.create_task(task4())
  
  asyncio.create_task(run_server())

  while True:
    print('IN MAIN ------')
    await asyncio.sleep(3)

#-----------------------------------------------------------------------------------    

utime.sleep(10)                      # time for me to reset terminal session

asyncio.run(main()) [/size] 

#-------------------------------------------------------------------------------------------------------------------------------
Any assistance would be most welcome :)

Regards Andrew

User avatar
jimmo
Posts: 2645
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: asyncio, server does not call handle_client

Post by jimmo » Mon Jul 11, 2022 4:48 am

arg wrote:
Sat Jul 09, 2022 1:24 pm
It is as though the handle_client does nothing.

Several other simple test tasks run as expected.
It appears there's something wrong with handling exceptions inside an "async with".

In uasyncio there's no "serve_forever" on the Server class, and so this is raising an exception and then terminating the server.

Perhaps we should add a serve_forever (and we should definitely fix whatever's going on with why this didn't show an exception), but in the meantime you can use an asyncio.Event to wait for shutdown (and set that event whereever appropriate).

Code: Select all

shutdown_event = asyncio.Event()

....

async def run_server():
    server = await asyncio.start_server(handle_client,"0.0.0.0",80)
    
    async with server:
        await shutdown_event.wait()
        

User avatar
jimmo
Posts: 2645
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: asyncio, server does not call handle_client

Post by jimmo » Mon Jul 11, 2022 5:26 am

Looks like there was a bug in the way start_server works... Raised a PR here https://github.com/micropython/micropython/pull/8895

arg
Posts: 6
Joined: Wed Jul 06, 2022 8:50 am

Re: asyncio, server does not call handle_client

Post by arg » Mon Jul 11, 2022 8:01 am

Hi Jimmo, thanks for the prompt response, ill try your solution shortly.

I was completely at a stop, it did not occur to me that an exception would not be forthcoming

Regards Andrew

arg
Posts: 6
Joined: Wed Jul 06, 2022 8:50 am

Re: asyncio, server does not call handle_client

Post by arg » Mon Jul 11, 2022 8:33 am

Hi Jimmo :)


# --------------------------------------------------------------------------------

# https://stackoverflow.com/questions/485 ... ng-asyncio
async def handle_client(reader:StreamReader,writer :StreamWriter):

print('in handle_client')

request = None
while request != 'quit':
request = (await reader.read(2)).decode('utf8')
print(request)
response = str(eval(request)) + '\n'
writer.write(response.encode('utf8'))
await writer.drain()
writer.close()


# --------------------------------------------------
# shutdown_event code made possible by Jimmo through micropython forum
shutdown_event = asyncio.Event()
async def run_server():
print('in run_server')
server = await asyncio.start_server(handle_client,local_IP,local_port)
async with server: await shutdown_event.wait()
print('leaving run_server')
#----------------------------------------------------------------------------------


"in run_server" printed otherwise no change in function for me. No exceptions printed.
Does it matter that i am using the DGRAM format to communicate with the pyboard

User avatar
jimmo
Posts: 2645
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: asyncio, server does not call handle_client

Post by jimmo » Mon Jul 11, 2022 9:57 am

When i wrote the reply earlier I did test this on a pybd and it was working...
arg wrote:
Mon Jul 11, 2022 8:33 am
Does it matter that i am using the DGRAM format to communicate with the pyboard
but... if by DGRAM you mean datagram (i.e. UDP) then nope this won't work. start_server is TCP only in Micropython (not sure about CPython)

arg
Posts: 6
Joined: Wed Jul 06, 2022 8:50 am

Re: asyncio, server does not call handle_client

Post by arg » Tue Jul 12, 2022 10:43 am

Hi Jimmo :)

Yipeee :)

Here is my code that receives TCP ( SOCK_STREAM )
sends a message to a different IP ( non-asyncio ) and then responds to the client.

# https://stackoverflow.com/questions/485 ... ng-asyncio
async def handle_client(reader,writer):

print('in handle_client')

data = await reader.read(50)
request=data.decode('utf8').strip()

print(request)

# non-asyncio code here, works well, send a message elsewhere
try:
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.1.63',6001)) # works correctly
s.send('test')
s.close()
except Exception as e:
print('Sending a string to another IP failed: '+str(e))

response="hello back \n"
try:
writer.write(response.encode('utf8'))
await writer.drain()
except Exception as e:
print('keh '+str(e))

reader.close()
writer.close()

# --------------------------------------------------
# shutdown_event code made possible by Jimmo through micropython forum
shutdown_event = asyncio.Event()
async def run_server():

server = await asyncio.start_server(handle_client,local_IP,local_port)
async with server: await shutdown_event.wait()


----------------------------------------------------------------------------------------------------------
this is sample output in Putty:
The numbers are free memory, I was checking for any memory leaks

IN MAIN ------174576
in task 1
in task 2
in task 4
in task 3
in task 2
in task 1
in task 4
in task 3
in task 4
in handle_client
Hello
in task 2
in task 1
in task 3
in task 4
in task 2
IN MAIN ------173760
in task 1
in task 3
in task 4

Thanks for your assistance Jimmo, i did not know where else to pursue on my own ( lets get those exception messages in place )

Regards Andrew

User avatar
jimmo
Posts: 2645
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: asyncio, server does not call handle_client

Post by jimmo » Tue Jul 12, 2022 11:40 am

arg wrote:
Tue Jul 12, 2022 10:43 am
Yipeee
Great! Glad it's working.
arg wrote:
Tue Jul 12, 2022 10:43 am
( lets get those exception messages in place )
Hopefully https://github.com/micropython/micropython/pull/8895 will be merged very shortly. Thanks for raising this!

Post Reply