2

I am using over 20 raspberry pis to control heating and other functions in my house. For instance each room has a pi (client) with a temperature sensor, which sends a message to another pi (server) at one of three manifolds to open or close a valve on the heating system. My problem is the amount of time the server takes to execute the bind instruction. A newly set up pi will typically take a few millisecond to execute the line, but soon the time becomes variable, sometimes milliseconds, usually seconds, but frequently tens of seconds or even hundreds of seconds.

typical code,

elapselp = default_timer()  # timing start
port = 12571                # port number, many different ones used
while bound == 0:
     try:
          s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          s1.bind(('', port))
          bound = 1
          elapselp1 = default_timer() - elapselp
          print ('bind time = ', elapselp1)

As stated above elapselp1 can be at the low millisecond level, or 200 seconds which causes significant problems.

I usually find I can get back to short times by changing the port number used, which means changing on all the clients, but after some time running happily the times will increase again. Rebooting or powering down does not help. I am using Raspberry 4s and Zero Ws, no difference. I suspect that some register is not clearing, but outside that am clueless. Can somebody advise please. I am running Rasparian 3.6 and Python3

Thank you for all your replies, here is the remainder of this section of the code.

As I’m not sure how to input his I’m breaking it down over a number of comments.

elapselp = default_timer()
port =12571
while bound == 0:
    try:
        s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
        s1.bind(('', port))
        bound = 1
        elapselp1 = default_timer()- elapselp
        print (‘bind time = ‘, elapselp2) 
    except:
        dummy = 1
        
    s1.listen(5)
    print ('waiting for input ', end='')
    while True:
        conn, addr = s1.accept()
        print ('connected by ', addr)
        conn.send('thank you'.encode())
        data = conn.recv(1024).decode()
        print ('data = ', data)
        time.sleep(5)
        conn.close()
        s1.close()
                
        if data == '10':
            startdaw = default_timer()
            GPIO.output(22, GPIO.LOW)
            print ('switch dining area heating off')
            h1 = 0
            dawl = edaw
            startdawr = default_timer() 
        elif data == '11':
            GPIO.output(22, GPIO.HIGH)
                
    ## A lot of other actions depending on data received here
    
        else:
            print ('another code ', data)
        if not data:
            break
            print ('yet another')

I have a number of Raspberry pi Zeros running the code for test along with 7 doing so as part of my control system. The performance is very erratic. One unit running through the code every 30 seconds in response to a client has been running over 5 days, majority of the bind times have been under 1 millsec, I see some between 1 and 10, but it has recorded one time of 130 seconds. Another unit which failed to bind for over two hours has now completed over 33,000 binds (this one just closes after the bind, no if statements), and the longest time for a bind is 710 msec.

If I take out the try/except I get no error message, it just drops through and loops back.

I hope there is some useful information in there.

johno
  • 21
  • 2
  • 1
    Hello and welcome to StackOverflow! Would you mind showing the rest of the `try` block? That is, do you have an `except` block after it? – Daniel Walker Jan 03 '23 at 19:51
  • 3
    Maybe [this](https://stackoverflow.com/a/6380198/477878) could help? – Joachim Isaksson Jan 03 '23 at 19:52
  • 4
    Try running `netstat -anp` and check if the ports are on `TIME_WAIT`, if so, the `SO_REUSEADDR` is a good option. – Bharel Jan 03 '23 at 19:54
  • 4
    It sounds like a lot of sockets in timed wait. After a socket closes the OS keeps the socket in a zombie state for (platform dependent but likely) 120 seconds. You could see if you can increase the number of sockets on the pi. Also, as soon as your sending is done you should `s1.shutdown(socket.SHUT_WR)` and when receiving is done do `s1.shutdown(socket.SHUT_RD)` so that fins and acks are sent on the channel as soon as possible. If you are doing a huge number of connects, perhaps you could cache and reuse an open connection. – tdelaney Jan 03 '23 at 20:06
  • Does this answer your question? [Python: Binding Socket: "Address already in use"](https://stackoverflow.com/questions/6380057/python-binding-socket-address-already-in-use) – Daniel Walker Jan 03 '23 at 20:32
  • 3
    What exception are you getting? Get rid of the try/except and give us the error message if any. Are you binding over and over again for some reason? – Mark Tolonen Jan 03 '23 at 20:41
  • Thank you for all your replies, here is the remainder of this section of the code. As I’m not sure how to input his I’m breaking it down over a number of comments. elapselp = default_timer() port =12571 while bound == 0: try: s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s1.bind(('', port)) bound = 1 elapselp1 = default_timer()- elapselp print (‘bind time = ‘, elapselp2) except: dummy = 1 . – johno Jan 11 '23 at 18:06
  • Why are you binding in a loop? What's the point of the try/except, if you then try to listen anyway? – gre_gor Jan 11 '23 at 18:56

0 Answers0