0

I am new to server development so please be kind... I am developing a test application that starts a flask-socketio server and after interacting with a clients, it needs to shutdown and open another instance. However this is not possible I get error

File "C:\Python39\lib\site-packages\eventlet\convenience.py", line 78, in listen
sock.bind(addr)
OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted

How can I programmatically shutdown the server? I looked in answers here How to stop flask application without using ctrl-c and using a process indeed does the trick. But I don't really want to have a separate process because sharing the variables between process is too tricky.

I also didn't understand from the same post how to send a request from the server to the server itself in order to shutdown the flask application. This is an example of my code

import socketio
import eventlet
import eventlet.wsgi
from flask import Flask, render_template
import socket
import threading
import time


ip_addr=socket.gethostbyname(socket.gethostname())
appFlask = Flask(__name__)
sio = socketio.Server( )  #engineio_logger=True,logger=True)
# wrap Flask application with engineio's middleware
app = socketio.Middleware(sio, appFlask)

@sio.on('connect')
def connect(sid, environ):
    print('connect ', sid)

@sio.on('message')
def message(sid, data):
    print('message '+data, data)

@sio.on('disconnect')
def disconnect(sid):
    print('disconnect ', sid)

@sio.on('result')
def result(sid,data):
    print('result ', sid)

def worker1():
    socket_port=3000
    eventlet.wsgi.server(eventlet.listen((ip_addr, socket_port)), app)


if __name__ == '__main__':

    sio.start_background_task(worker1)
    #   do some stuff and interact with the client
    sio.sleep(2)
    # how can I close  the server so that I can do the following?
    sio.start_background_task(worker1)

EDITED wit flask socket io functionality

import socketio
import eventlet
import eventlet.wsgi
from flask import Flask, render_template
import socket
import threading
import time
import requests
from flask import request
from flask_socketio import SocketIO

ip_addr=socket.gethostbyname(socket.gethostname())
socket_port=3000

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
sio = SocketIO(app)

@app.route('/stop')
def stop():
    sio.stop()

@sio.on('connect')
def connect(sid, environ):
    print('connect ', sid)

@sio.on('message')
def message(sid, data):
    print('message '+data, data)

@sio.on('disconnect')
def disconnect(sid):
    print('disconnect ', sid)

@sio.on('result')
def result(sid,data):
    print('result ', sid)


def worker1():
    eventlet.wsgi.server(eventlet.listen((ip_addr, socket_port)), app)



if __name__ == '__main__':

    eventlet_thr=sio.start_background_task(worker1)
    #   do some stuff and interact with the client
    sio.sleep(2)
    # now wait  that the server is stopped

    # invoke in a different process a request to stop

    eventlet_thr.join()


    # how can I close  the server so that I can do the following?
    sio.start_background_task(worker1)
zambs
  • 21
  • 8

1 Answers1

0

You are using the eventlet web server is seems, so the question is how to stop the eventlet web server, Flask-SocketIO has nothing to do with the server.

As a convenience, Flask-SocketIO provides the stop() method, which you have to call from inside a handler. I'm not sure if that will work when the server is running on a thread that is not the main thread though, you'll have to test that out.

So basically what you need to do is add an endpoint that forces the server to exit, maybe something like this:

@app.route('/stop')
def stop():
    sio.stop()
    return ''

So then you can start and stop the server as follows:

if __name__ == '__main__':
    thread = sio.start_background_task(worker1)
    #   do some stuff and interact with the client
    requests.get('http://localhost:5000/stop')
    thread.join()
Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152
  • Thank you for your suggestion and the clarification about the eventlet server. I tried the snippet above but the request never seem to reach the stop handler. The scripts just hang in the request line forever. – zambs Mar 15 '21 at 15:44
  • Make sure the URL is correct. Also note that I forgot to add a response on the stop handler, which I now added. – Miguel Grinberg Mar 15 '21 at 19:11
  • Thanks Miguel, I double checked the URL seems correct. After some debugging I released that in order to invoke sio.stop I need to use the flask socket io implementation (see EDITED code above). Secondly I need to send the request from a different process, so I created a new python file which I use to send the request. Lastly I see the request is received and processed and in case of eventlet a SystemExit exception is raised causing the entire python run to exit and therefore I cannot continue the script execution with the reopening of a new server instance – zambs Mar 16 '21 at 11:50
  • I mentioned in my response that I wasn't sure this would work when the server is running in a secondary thread. – Miguel Grinberg Mar 16 '21 at 13:52
  • Yes, I was aware of that, this why I tried to send the request from another python execution.That worked indeed but the sio.stop() raised assertion causes the main thread to exit, so I cannot open a new server instance after that. Thanks nevertheless! – zambs Mar 16 '21 at 15:35