flask and socket io - python

i am experimenting with flask and have a basic web page setup that gives me a data field to fill in. it all works ok, but i am having a problem with sending data via a socket connection to a server. the code is below:
from flask import Flask, render_template, request
import socket
import sys
app = Flask(__name__)
app.static_folder = 'static'
HOST, PORT = '', 8888
#app.route('/')
def index():
return render_template("index.html")
#app.route('/success', methods=['POST'])
def success():
if request.method == 'POST':
if request.form['Update'] == 'Update':
messsage_name = request.form["message_name"]
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as soc:
# connect to server if we have a post
soc.connect((HOST, PORT))
soc.sendall(bytes(messsage_name + "\n", "utf-8"))
return render_template("index.html")
if __name__ == '__main__':
app.debug = True
app.run()
I want to open the socket once then send data via it each time the update button is pressed, at present the only way i can get it to work is keep opening the socket as in the above code in success. I don't want the socket to close until the flask app quits.
whats the best way to achieve my goal
thanks

I think your title is wrong. In your example there is no use of socketIO library.
For using socketIO in your flask application, you need to install the library like this:
pip install flask-socketio
And then you can import it in your python file as:
from flask_socketio import SocketIO, emit
You can then use socketIO and emit some messages/data to your web page.
By the way your sockets, initialized as before, will live as long as your Flask server is on. More information available over there.
If your goal is to use the Python sockets, then you have to edit your question title.

Related

Closing flask-socket io server programmatically

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

Chrome Native Messaging - Execute the host manually

i'm trying to create a web extension using native messaging that can interact with a Web API. So the idea is when someone sends a message through the API, the extension also receive it.
I follow the steps of the firefox example. So far so good, i was able to communicate between the host and the extension.
Here is my host code, using the flask framework:
import json
import sys
import struct
import threading
import os
from flask import Flask, request, jsonify, Response, abort
# Read a message from stdin and decode it.
def get_message():
raw_length = sys.stdin.read(4)
if not raw_length:
sys.exit(0)
message_length = struct.unpack('=I', raw_length)[0]
message = sys.stdin.read(message_length)
return json.loads(message)
# Encode a message for transmission, given its content.
def encode_message(message_content):
encoded_content = json.dumps(message_content)
encoded_length = struct.pack('=I', len(encoded_content))
return {'length': encoded_length, 'content': encoded_content}
# Send an encoded message to stdout.
def send_message(encoded_message):
sys.stdout.write(encoded_message['length'])
sys.stdout.write(encoded_message['content'])
sys.stdout.flush()
def get_message_background():
while True:
message = get_message()
if message == "ping":
send_message(encode_message("pong"))
thread = threading.Thread(target=get_message_background)
thread.daemon = True
thread.start()
app = Flask(__name__)
#app.route("/test", methods=['GET'])
def test():
send_message(encode_message('testing'))
return 'testing'
app.run('localhost', 5001, debug=True)
With this code i receive a ping and respond a pong.
The problem is when i try to run that code on the terminal.
The native messaging communicates over stdio and when i'm run my script on the terminal, the terminal became the standard input and output.
If i just load the extension, the flask not start.
Someone has solved this problem?
PS: Sorry for my english

Flask generating requests with random port

Am trying to generate a get request from a flask server to another, on destination side when I print the port, I keep getting random ports with each request
CLIENT:
from flask import Flask, redirect, request
import requests
app = Flask(__name__)
#app.route('/acqlock/<resource_name>')
def acquire_resource(resource_name):
print request.url
response = requests.get('http://127.0.0.1:8080/acqlock/' + resource_name)
return response.text
if __name__ == "__main__":
app.run(host="localhost", port=8081)
SERVER :
from flask import Flask, redirect, request
app = Flask(__name__)
#app.route('/')
#app.route('/acqlock/<resource_name>')
def acquire_lock(resource_name):
print request.url
print request.environ.get('REMOTE_PORT')
if __name__ == "__main__":
app.run(port=int("8080"))
it keeps printing http://127.0.0.1:8080/acqlock/file 58077 eventhough I was expecting it to print http://127.0.0.1:8081 8081 as the server is generating the request
This is normal. Remember that requests is the client here, it has to create a new HTTP connection to another server. TCP connections on the client side need a port as well, and when you create a socket to a remote server you are assigned a port number by the OS for the client-side of the connection.
That you are making this outgoing HTTP connection in the context of an incoming HTTP connection is neither here nor there. It is a different connection, in a different direction.
If you need to identify where the request came from, add information to the request. You can add custom headers, a cookie, query parameters, or post data.

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