Async TCP Server

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
Post Reply
andutzicus
Posts: 5
Joined: Tue Apr 04, 2017 5:00 am

Async TCP Server

Post by andutzicus » Sat May 27, 2017 4:34 pm

Hello,

I'm trying to make ESP do some other things while waiting for a connection from a client. I found that using s.setblocking(true) can help with this. So i was trying multiple ways of pseudo-multitasking like this:

Code: Select all

import socket
import time

def check_conn():    
    cl, addr = s.accept()
    data = cl.recv(20)
    print(data)
    cl.close()

def do_something_else():
    print("doing things")

addr = socket.getaddrinfo('192.168.0.121', 868)[0][-1]
s = socket.socket()
s.setblocking(False)
s.bind(addr)
s.listen(1)

while True:
    check_conn()
    do_something_else()
    time.sleep_ms(50)
This works if i set blocking as true. Anyone encountered this before?

Beta_Ravener
Posts: 35
Joined: Tue Aug 09, 2016 6:56 pm

Re: Async TCP Server

Post by Beta_Ravener » Sat May 27, 2017 7:22 pm

What's your problem exactly? Is it not working in non-blocking mode? If so, what is the issue - does it stop executing script, you get an error or something else?

I can see a problem with your code when you use non-blocking mode. You start to listen and then periodically check connection. In blocking mode, the accept inside check_conn function will block waiting for connection. When you set blocking to false, this happens (copied from Stack Overflow):
If the listen queue is empty of connection requests and O_NONBLOCK is not set on the file descriptor for the socket, accept() shall block until a connection is present. If the listen() queue is empty of connection requests and O_NONBLOCK is set on the file descriptor for the socket, accept() shall fail and set errno to [EAGAIN] or [EWOULDBLOCK].
While the definition is for C implementation, I doubt that Python behaves differently, so you would get some kind of error. Or you might not get an error but the socket may be set to None, in which case reading from it with recv will cause exception. Classic approach to solve this would be using select function, that can tell if there are any connections. However, I think micropython still does not have that one implemented, so you should at least check for errors on accept/recv and act as there was no connection when they fail.

andutzicus
Posts: 5
Joined: Tue Apr 04, 2017 5:00 am

Re: Async TCP Server

Post by andutzicus » Thu Jun 01, 2017 7:00 am

Ok, i was being ambiguous. Thank you for your reply.

So, in blocking mode everything is ok. Changing to non-blocking will require you to do some polling. My problem was that i couldn't find a way to poll. I will explain the problem and the solution i found, in the same time.

First of all, this is what happens when you print the socket:

Code: Select all

>>> print(s)
<socket state=0 timeout=0 incoming=0 off=0>
You (being the client, ESP being the server) initiate a connection and incoming becomes a value larger than 0 (i didn't check what that hex value is), so i was polling the length of this string.
Here comes my problem: You accept the connection and incoming becomes 0 and socket_state becomes 0. But you now don't check s socket anymore, instead, you will check cl socket. Which has socket_state = 2, meaning it's connected.
You send actual data and socket_state of cl becomes 3 and now it's time to extract data.
ESP now send back a response to you and immediately closes cl socket.

Code: Select all

 #Start TCP server
    addr = socket.getaddrinfo('192.168.0.121', 868)[0][-1]
    s = socket.socket()
    s.setblocking(False)
    s.bind(addr)
    s.listen(1)
    while True:
        start = time.ticks_ms()
        socket = (str)(s)
        if len(socket) > 43:
            cl, addr2 = s.accept()
            cl_str = (str)(cl)
            while cl_str[14] == "2":
                cl_str = (str)(cl)
            data = cl.recv(32)
            print(data)
            cl.close()
            delta = time.ticks_diff(time.ticks_ms(), start)
            print(delta)
In the meanwhile you can do some other short things, in my case i want to update the status of a PWM pin once 50mS.

pfalcon
Posts: 1155
Joined: Fri Feb 28, 2014 2:05 pm

Re: Async TCP Server

Post by pfalcon » Sun Jun 04, 2017 11:18 am

Did you try to read/search forum? E.g., viewtopic.php?f=16&t=2966 should be hard to miss.
Awesome MicroPython list
Pycopy - A better MicroPython https://github.com/pfalcon/micropython
MicroPython standard library for all ports and forks - https://github.com/pfalcon/micropython-lib
More up to date docs - http://pycopy.readthedocs.io/

Post Reply