Closing flask-socket io server programmatically - python

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)

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()

Related

Listening for RabbitMQ and running flask on same server

I have a Flask application as such
from flask import Flask
from flask_restful import Resource, Api
from mq_handler import MessageBroker
import pika
app = Flask(__name__)
api = Api(app)
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
mb = MessageBroker(connection)
class HelloWorld(Resource):
def get(self):
mb.run()
return {'hello': 'world'}
class LogHandler(Resource):
def get(self, table):
return {'TableName': table}
api.add_resource(HelloWorld, '/')
api.add_resource(LogHandler, '/log/<string:table>')
if __name__ == '__main__':
app.run(debug=True)
I have added a MessageBroker class to handle all my rabbitMq messages
import pika
import json
class MessageBroker:
def __init__(self, connection):
self.connection = connection
self.channel = connection.channel()
def run(self):
self.channel.start_consuming()
self.channel.basic_consume(queue='logs',
auto_ack=True,
on_message_callback=self.handle_log)
self.channel.start_consuming()
def handle_log(self, ch, method, properties, body):
decoded_content = body.decode('utf-8')
json_payload = json.loads(decoded_content)
print(" [x] Received %r" % json_payload['message'])
I have tried different solutions, but have can I get both services to run simultaneously on the same server? can somebody explain that please?
In general.. how is it possible to have several services running listening on my flask server?
I am not sure about running the consumer on an end-point will be a good idea. Because, when you start a consumer it runs an IO loop to fetch and process messages from the server continuously. The loop will not exit unless it is done externally or any exception in the message processing causing the connection to close. Can you please state your scenario for running the consumer in the end-point?

Python-SocketIO server won't emit from the main section of the program

I have a pyhton-socketio server that servers on port 8000 and handles connections perfectly. I want to emit the following emit message every 2 seconds. When emitting the client doesn't receive a message. If I emit from where I point out in the comment it works perfect.
How can I edit this to be able to emit from inside the while loop successfully?
The python server code:
import socketio
import eventlet
import threading
import time
from flask import Flask, render_template
sio = socketio.Server()
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
# as a decorator:
#sio.on('connect')
def connect_handler(sid, environ):
print('IP->' + environ['REMOTE_ADDR'])
# If I emit here it works e.g. sio.emit('status-update', {'core0_in': 8, 'core1_in': 12,'cpu_usage_in': 5, 'users': 7})
#sio.on('disconnect')
def disconnect(sid):
print('disconnect ', sid)
class Server(threading.Thread):
def __init__(self, thread_id):
threading.Thread.__init__(self)
self.threadID = thread_id
def run(self):
print("Starting " + self.name)
serve()
def serve():
if __name__ == '__main__':
global app
# wrap Flask application with socketio's middleware
app = socketio.Middleware(sio, app)
# deploy as an eventlet WSGI server
eventlet.wsgi.server(eventlet.listen(('', 8000)), app)
server_thread = Server("Server-thread")
server_thread.start()
while True:
print("Emitting...")
sio.emit('status-update', {'core0_in': 8, 'core1_in': 12,'cpu_usage_in': 5, 'users': 7}) # when emitting here the client doesn't receive anything
time.sleep(2)

How to run python-socketio (eventlet WSGI server) over HTTPS

I want to run the following eventlet WSGI server over HTTPS. I am trying to connect to the python server from JavaScript on my HTTPS enabled web-server.
I would like the answer to describe how I would change this code below to work with HTTPS.
import socketio
import eventlet
import eventlet.wsgi
from flask import Flask, render_template
sio = socketio.Server()
app = Flask(__name__)
#app.route('/')
def index():
"""Serve the client-side application."""
return render_template('index.html')
#sio.on('connect', namespace='/chat')
def connect(sid, environ):
print("connect ", sid)
#sio.on('chat message', namespace='/chat')
def message(sid, data):
print("message ", data)
sio.emit('reply', room=sid)
#sio.on('disconnect', namespace='/chat')
def disconnect(sid):
print('disconnect ', sid)
if __name__ == '__main__':
# wrap Flask application with engineio's middleware
app = socketio.Middleware(sio, app)
# deploy as an eventlet WSGI server
eventlet.wsgi.server(eventlet.listen(('', 8000)), app)
This code was take from here
To run a Evenlet WSGI server over HTTPS all that’s needed is to pass an SSL-wrapped socket to the server() method like so:
wsgi.server(eventlet.wrap_ssl(eventlet.listen(('', 8000)),
certfile='cert.crt',
keyfile='private.key',
server_side=True),
app)

Serial Communication, Flask-SocketIO, and Python Multithreading

My question is related to having an Arduino Uno communicate data through a socket to another client app. [A buzzer system communicating to a Jeopardy!-esque game frontend] To goal is to have the 'lockout' event emit.
Currently, the Arduino is running on its own thread and the Flask-SocketIO server is running as the main process. All code works, including the print statement saying "Emitting Socket", except for the line emitting the socket data after.
I feel like this is just a multithreading issue, but my experience with multithreading is minimal.
Suggestions?
# https://pymotw.com/2/threading/
# https://flask-socketio.readthedocs.org/en/latest/
import serial, time, threading
from flask import Flask, render_template
from flask_socketio import SocketIO
ser = serial.Serial('/dev/tty.usbmodem3d11', 9600, dsrdtr=1)
PORT = 3000
# Needed b/c Macs & DTR
time.sleep(5)
def getSerialData():
while True:
stuff = str(ser.readline().decode("utf-8"))
doEmit(1)
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
def doEmit(pNo):
print("Emitting Socket")
socketio.emit('lockout', {'playerNo': 1})
serialThread = threading.Thread(name='serialThread', target=getSerialData)
serialThread.start()
#socketio.on("questionRead")
def on_questionRead(data):
print("-------Start-------")
ser.write(b'y\r')
#socketio.on("resetLockout")
def on_resetLockout(data):
resetLockout()
def resetLockout():
print("--------Reset--------")
ser.write(b'n\r')
if __name__ == '__main__':
socketio.run(app, '127.0.0.1', PORT)
You emit a 'lockout' message here:
def doEmit(pNo):
print("Emitting Socket")
socketio.emit('lockout', {'playerNo': 1})
I don't see where you're providing the function to receive this emitted code. Perhaps adding something like this with the appropriate adjustments:
#socketio.on("lockout")
def on_lockout(data):
print("-------Lockout Player", data['playerNo'] , "-------")

gevent-socketio send message from thread

I would like to use gevent-socketio to send messages from a worker thread and update all connected clients on the status of the job.
I tried this:
from flask import Flask, render_template
from flask.ext.socketio import SocketIO, send, emit
import threading
import time
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
#socketio.on('message')
def handle_message(message):
send(message, broadcast=True)
#app.route('/')
def index():
return render_template('index.html')
def ping_thread():
while True:
time.sleep(1)
print 'Pinging'
send('ping')
if __name__ == '__main__':
t = threading.Thread(target=ping_thread)
t.daemon = True
t.start()
socketio.run(app)
And it gives me this error:
RuntimeError: working outside of request context
How do I send messages from a function that doesn't have the #socketio.on() decorator? Can I use gevent directly to send messages to socketio?
From this section of the documentation:
Sometimes the server needs to be the originator of a message. This can be useful to send a notification to clients of an event that originated in the server. The socketio.send() and socketio.emit() methods can be used to broadcast to all connected clients:
def some_function():
socketio.emit('some event', {'data': 42})
This emit is not from from flask.ext.socketio import SocketIO, send, but instead called on your socketio variable from socketio = SocketIO(app). Had you done socketio_connection = SocketIO(app), then you'd be calling socketio_connection.emit() to broadcast your data.

Categories

Resources