0

I'm working on a camera endpoint for an IoT application and I want to start and stop a flask app on command to show a webpage with streaming camera data. I have all the individual pieces working but it's failing when I put them together.

If I start a flask process after starting another thread it complains that address is already in use. Here's a stripped down example:

#!/usr/bin/env python3

import os
import threading
from flask import Flask
import socket
import time
from multiprocessing import Process

app = Flask(__name__)

def main():
    start_thread(udp_listener)
    start_process(runflask)

    while True:
        time.sleep(1)

def start_thread(function, arguments=()):
    th = threading.Thread(target=function, args=arguments)
    th.daemon = True
    th.start()

def start_process(function):
    server = Process(target=function)
    server.start()
    while True:
        time.sleep(60)
    server.terminate()
    server.join()

def udp_listener():
    while True:
        with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
            s.bind(('', 9000))
            print('udp listening on port 9000')
            while True:
                data, server = s.recvfrom(4069)
                print('received:')

def runflask():
    app.run(host='0.0.0.0', port=8001, debug=True)

if __name__ == "__main__":
    main()

Comment out start_thread() and just run start_process() and it's ok. Comment out start_process() and just run start_thread() and it's ok. Run both and get an address already in use error even though they're listening on different ports.

Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
    self.run()
File "/usr/lib/python3.5/threading.py", line 862, in run
    self._target(*self._args, **self._kwargs)
File "./webcam_test.py", line 35, in udp_listener
    s.bind(('', 9000))
OSError: [Errno 98] Address already in use

I want to run the flask app in a way that will let me start and stop it on command. Should I be doing it a different way?

user903115
  • 133
  • 1
  • 6

2 Answers2

0

I was able to resolve this by using a ServerThread as specified here: How to stop flask application without using ctrl-c

It's important to note that calling this ServerThread automatically blocks so if you want an interruptible thread, you need to instantiate this as the child of another thread. My design already spawned threads for each camera mode so now I have a thread calling a thread calling a thread :).

I still don't know why flask, when run as a process, would complain about unrelated listen sockets but now I have a workaround.

user903115
  • 133
  • 1
  • 6
0

Don't how relevant this still is, but:

From a quick glance I don't see any place where the socket you are binding (s.bind(('', 9000))) is being closed. Since it's on a loop it tries to bind a socket that's in use again, hence the error? It should be stopped before binded again:

s.shutdown(1)
s.close()

If this is the case, the first solution I suggest is to close the socket properly, and not have it started in the loop (why do you bind the socket in loop in the first place?)

If this alone does not help, allow the socket to reuse the address:

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

Python: Binding Socket: "Address already in use"