When I try to send a socket message outside from the SocketIO event context, the message does not arrive at the client.
Method outside of the context:
#main.route('/import/event', methods=['POST'])
def update_client():
from .. import socketio
userid = request.json['userid']
data = request.json
current_app.logger.info("New data: {}".format(data))
current_app.logger.info("Userid: {}".format(userid))
socketio.emit('import', data, namespace='/events', room=userid)
return 'ok'
I also tried:
with current_app.app_context():
socketio.emit('import', data, namespace='/events', room=userid)
On the SocketIO Context 'on.connect'
#socketio.on('connect', namespace='/events')
def events_connect():
current_app.logger.info("CONNECT {}".format(request.namespace))
userid = request.sid
current_app.clients[userid] = request.namespace
The method update_client will be called from a thread.
On the Client side:
$(document).ready(function(){
var socket = io.connect('http://' + document.domain + ':' + location.port +'/events');
var userid;
socket.on('connect', function() {
console.log("on connect");
});
socket.on('import', function (event) {
console.log("On import" +event);
});
When I call the emit('import', 'test') in the #socketio.on('connect') method the messages arrives at the client and the log message is printed.
There is an example in the documentation:
#app.route('/ping')
def ping():
socketio.emit('ping event', {'data': 42}, namespace='/chat')
Do I miss something or why does the message not arrive at the client?
Edit:
The socketio is created in the app/__init__.py function
socketio = SocketIO()
create_app():
app = Flask(__name__)
socketio.init_app(app)
manage.py
from app import socketio
if __name__ == '__main__':
socketio.run(app)
Flask-SocketIO==2.6
eventlet==0.19.0
I found a solution.
When I run the application with the flask internal server, the messages are not received by the client.
python manage.py run
But when I run the server with gunicorn all works like a charm.
So the solution here is to use the gunicorn with eventlet.
gunicorn --worker-class eventlet -w 1 manage:app
I use Flask 0.11 with Flask-Migrate 2.0. Perhaps I missed something, since Flask 0.11 has a new startup command.
Related
I'm currently following a Udemy course that's having me use flask and socketio to use a neural network model to drive a simulated car. However, as he's explaining the basics of how flask and socketio work, he had us write this code:
import socketio
import eventlet
from flask import Flask
sio = socketio.Server()
app = Flask(__name__)
#sio.on('connect')
def connect(sid, environ):
print('Connected')
if __name__ == "__main__":
app = socketio.Middleware(sio, app)
eventlet.wsgi.server(eventlet.listen(('', 4567)), app)
Which is supposed to print "Connected!" to the console when we connect to the server. Now, I get this message when I run it, so I'm pretty sure I'm connected.
(7532) accepted ('127.0.0.1', 49374)
But it's refusing to print "Connected!" when I connect like it's supposed to, no matter what I try.
EDIT:
So, I'm still not sure what the root cause of this is, but I found out how to fix it.
conda install python-engineio==3.13.2
conda install python-socketio==4.6.1
You might need to run anaconda as an administrator. If so, search for "Anaconda Powershell Prompt" then run it as an admin.
socketio uses special protocol so you need special client to use it.
At least
import socketio
sio = socketio.Client()
con = sio.connect('http://0.0.0.0:4567')
sio.wait()
I will not work with web browser. With web browser you can see only accepted.
Browser have to load web page which uses special JavaScript module to use socketio.
You can find more details in socketio documentation: Client
EDIT:
And here server which you can test with web browser.
When you open http://0.0.0.0:4567 in browser then index() sends to browser HTML with JavaScript code which loads special library and uses socketio to send own event. And you should see Connected, my event. When you close page or browser then you should see Disconnected
It is based on example from documentation for flask-socketio
import socketio
import eventlet
from flask import Flask
sio = socketio.Server()
app = Flask(__name__)
#app.route('/')
def index():
return """
Hello World!
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js" integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA==" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
var socket = io();
socket.on('connect', function() {
socket.emit('my event', {data: 'Im connected!'});
});
</script>
"""
#sio.on('connect')
def connect(sid, environ):
print('Connected')
#sio.on('disconnect')
def disconnect(sid): # without `environ`
print('Disconnected')
#sio.on('my event')
def my_event(sid, environ):
print('my event')
if __name__ == "__main__":
app = socketio.Middleware(sio, app)
eventlet.wsgi.server(eventlet.listen(('', 4567)), app)
I am using python socketio for communication and it works well for http. Have a problem when upgraded it to work with SSL.
I made a self-signed root certificate (CA), and issued server.cert and server.key. I told the computer to trust the CA. After that, I added the server.cert and server.key on the flask-socketio server side. And the code looks like this:
from flask import Flask, render_template
from flask_socketio import SocketIO
from flask_socketio import Namespace
app = Flask(__name__, template_folder="templates")
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
# Create a URL route in our application for "/"
#app.route('/')
def home():
"""
This function loads the homepage
"""
return render_template('index.html')
class MyCustomNamespace(Namespace):
def on_connect(self):
print("Client just connected")
def on_disconnect(self):
print("Client just left")
def on_messages(self, data):
print(f"\nReceived data from client: \n {data}\n")
return data
socketio.on_namespace(MyCustomNamespace('/channel_A'))
if __name__ == "__main__":
socketio.run(app, host="192.168.0.28", port=2000, certfile="server.crt", keyfile="server.key", server_side=True, debug=True)
#socketio.run(app, host="192.168.0.28", port=2000, debug=True)
The code for client connection is simply:
import socketio
sio = socketio.Client()
def message_received(data):
print(f"Message {data} received")
#sio.on('connect', namespace="/channel_A")
def on_connect():
print("Connect...")
#sio.on('disconnect', namespace="/channel_A")
def on_disconnect():
print(f"Disconnected from server")
if __name__ == '__main__':
sio.connect('https://192.168.0.28:2000', namespaces="/channel_A")
emit_times = 0
is_emit = True
data = '{"data": "foobar"}'
while is_emit:
sio.emit("messages", data, namespace="/channel_A", callback=message_received)
emit_times += 1
if emit_times > 1:
is_emit = False
sio.disconnect()
I am using python-socketio (https://python-socketio.readthedocs.io/en/latest/client.html#disconnecting-from-the-server) for client end.
When the server gets started, the website works well and the connection is secure. The command line looks like this:
* Restarting with stat
* Debugger is active!
* Debugger PIN: 142-782-563
(3484) wsgi starting up on https://192.168.0.28:2000
When SocketIO client tries to connect with the server, the connection is refused and on the server end, the error is finally thrown like this:
ssl.SSLError: [SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca (_ssl.c:2488)
I think I probably miss something. Any ideas? Thanks in advance!
It seems that this is a bug in a newer SocketIO version. You can try to downgrade to 2.x.x:
pip install python-socketio<3.0.0 --force-reinstall
So I am making an app in Flask and I am using RabbitMQ as message broker and also backend Celery worker. I also use SocketIO in order to report back the celery worker status to the client. When I am running my app I get the following error:
I appreciate if you let me know why do I get this error.
app.py
app = Flask(__name__)
app.config['SECRET_KEY'] = ''
app.config.update(
CELERY_BROKER_URL = 'amqp://localhost//',
CELERY_RESULT_BACKEND='amqp://localhost//'
)
socketio = SocketIO(app, message_queue='amqp://')
celery = make_celery(app)
#app.route('/')
def my_form():
return render_template("form.html")
JavaScript
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port );
make_celery module
def make_celery(app):
celery = Celery(app.import_name, backend=app.config['CELERY_RESULT_BACKEND'],
broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)
TaskBase = celery.Task
class ContextTask(TaskBase):
abstract = True
def __call__(self, *args, **kwargs):
with app.app_context():
return TaskBase.__call__(self, *args, **kwargs)
celery.Task = ContextTask
return celery
Oops, the error message has been copy/pasted from another module, and I forgot to update it. The message should have read "Kombu requires a monkey patched socket library to work with gevent".
Basically this is saying that without monkey patching, gevent is going to block when socket operations are issued. See http://www.gevent.org/gevent.monkey.html for more details about this.
I have an ordinary Flask application, with just one thread to process requests. There are many requests arriving at the same time. They queue up to wait for be processed. How can I get the waiting time in queue of each request?
from flask import Flask, g
import time
app = Flask(__name__)
#app.before_request()
def before_request():
g.start = time.time()
g.end = None
#app.teardown_request
def teardown_request(exc):
g.end = time.time()
print g.end - g.start
#app.route('/', methods=['POST'])
def serve_run():
pass
if __name__ == '__main__':
app.debug = True
app.run()
There is no way to do that using Flask's debug server in single-threaded mode (which is what your example code uses). That's because by default, the Flask debug server merely inherits from Python's standard HTTPServer, which is single-threaded. (And the underlying call to select.select() does not return a timestamp.)
I just have one thread to process requests.
OK, but would it suffice to spawn multiple threads, but prevent them from doing "real" work in parallel? If so, you might try app.run(..., threaded=True), to allow the requests to start immediately (in their own thread). After the start timestamp is recorded, use a threading.Lock to force the requests to execute serially.
Another option is to use a different WSGI server (not the Flask debug server). I suspect there's a way to achieve what you want using GUnicorn, configured with asynchronous workers in a single thread.
You can doing something like this
from flask import Flask, current_app, jsonify
import time
app = Flask(__name__)
#app.before_request
def before_request():
Flask.custom_profiler = {"start": time.time()}
#app.after_request
def after_request(response):
current_app.custom_profiler["end"] = time.time()
print(current_app.custom_profiler)
print(f"""execution time: {current_app.custom_profiler["end"] - current_app.custom_profiler["start"]}""")
return response
#app.route('/', methods=['GET'])
def main():
return jsonify({
"message": "Hello world"
})
if __name__ == '__main__':
app.run()
And testing like this
→ curl http://localhost:5000
{"message":"Hello world"}
Flask message
→ python main.py
* Serving Flask app "main" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
{'start': 1622960256.215391, 'end': 1622960256.215549}
execution time: 0.00015807151794433594
127.0.0.1 - - [06/Jun/2021 13:17:36] "GET / HTTP/1.1" 200 -
I'm stuck in development of socket.io with Python. I'm using this lib
I got a chat app running by using this android part and with the lib sample. I want to trigger an event from the server side from a separate file. Here's my code.
import socketio
import eventlet
from flask import Flask, render_template
sio = socketio.Server(logger=True, async_handlers= True)
app = Flask(__name__)
eventlet.monkey_patch()
#sio.on('connect', namespace='/d')
def connect(sid, environ):
print('connect ', sid)
pass
#sio.on('messaget', namespace='/d')
def messaget(sid, data):
print('message ', data)
# sio.emit('messaget', data, namespace='/d')
# sendmsg("YO YO")
#sio.on('disconnect', namespace='/d')
def disconnect(sid):
print('disconnect ', sid)
def start_socket(app):
# wrap Flask application with socketio's middleware
app = socketio.Middleware(sio, app)
eventlet.wsgi.server(eventlet.listen(('', 8000)), app)
def sendmsg(data):
my_data= { 'text': data };
sio.emit('messaget', my_data, namespace='/d')
start_socket(app)
I'm calling sendmsg("dipen") from my another python file. I'm getting a log emitting event "messaget" to all [/d] but android app is not getting any messages. And it work's if event is emitting from the Android app. I tried with the NodeJs code and it worked for the NodeJs code so I'm pretty sure that something is wrong in my Python code. Hope that someone could save me from this.
Send a message from Android client. Does your Python code get it? If not, check if you have connected to the same namespace.