I'm trying to create a time delay within a server-side script of a flask web socket app.
Ultimately, I want the server to be handling many simultaneous requests, and to be able to emit back to the client two packets with a fixed time interval between.
When I use time.sleep(x) between two flask_socketio.emit statements, the client receives the socket emit events together, after the sleep has been completed.
How can I achieve Emit X; wait Y seconds; emit Z in a python flask application?
Server-side code excerpt:
from flask import Flask, request
from flask_socketio import SocketIO, join_room, emit
app = Flask(__name__)
socketio = SocketIO(app)
#socketio.on('ping')
def ping(appState):
"""send 2 pings, between a time interval"""
room = appState["sessionID"]
emit('serverPingResponse', {'room': room, 'msg':"Ping Received by Server"})
time.sleep(5)
emit('serverPingResponse', {'room': room, 'msg':"2nd time-delayed ping"})
return
Client-side code excerpt:
var socket = io.connect('http://' + document.domain + ':' + location.port);
socket.on("serverPingResponse", function(msg){
// listen to server ping and print the message to console
let d = new Date();
console.log("ping received at "+d.toLocaleTimeString(), msg)
});
Console Output
pinging server...
ping received at 10:43:14 AM
Object { room: "wvdhj01f3p", msg: "Ping Received by Server" }
ping received at 10:43:14 AM
Object { room: "wvdhj01f3p", msg: "2nd time-delayed ping" }
Desired output would be for the first ping to be received at 10:43:09 and the second at 10:43:14
You are using the time.sleep() function, which I'm guessing is blocking your server. Try using socketio.sleep() instead, which would do a cooperative sleep compatible with the async framework that you are using (eventlet, gevent).
Related
I have flask-socketio as backend and flutter as frontend. I am using flutter socket-io-client to connect to flask-socektio. It connects but I am receiving these continous messages on flask side
Sending packet PING data None
Received packet PONG data None
Sending packet PING data None
Received packet PONG data None
Sending packet PING data None
Received packet PONG data None
Sending packet PING data None
Received packet PONG data None ...... and so on
I wanted to get rid of this. How do I do it? also when I am sending/ emiting any data from frontend, the
socket.on('event' , (data)=>print(data) method prints null. So how do I send data from socketio event from backend to frontend? also I do I stop getting those messaged on PING PONG on server side?
Here is my flask code
from flask import Flask, request, jsonify
from flask_socketio import SocketIO
app = Flask(__name__)
app.secret_key = 'secret'
socketio = SocketIO(app,cors_allowed_origins="*")
app.debug = True
#app.route('/', methods=['GET'])
def index():
return 'Welcome!'
#socketio.on('connect')
def test_connect():
print('Client Connected')
#socketio.on('disconnect')
def test_disconnect():
print('Client disconnected')
#socketio.on('test')
def test():
print('Testing')
// i want to return some data to frontend here, how do I do it?
if __name__ == '__main__':
socketio.run(app,debug=True,host='0.0.0.0',port=5000)
Here is my flutter socket code
//using socket-io-client
IO.Socket socket = IO.io('http://192.16x.x.x:3000/', <String, dynamic>{
'transports': ['websocket']
});
socket.onConnect((_) {
print('connect');
});
scoket.on('test',(data)=>print(data)); //printing here the data received from backend
socket.onDisconnect((_) => print('disconnect'));
I have the similar problem in FastAPI (another Python framework similar with Flask).
Found a perfect solution here by using loguru.
This solution is for uvicorn web server, may need some change to suit Flask one
I'm having a lot of difficulty with a very simple task. I'm attempting to set up a socket.io client in node js, which should then communicate with a local socket.io server setup in python (using the python bindings here. The issue I'm having is the server is detecting the client, but the client never seems to receive the 'connect' event. I suspect this is an issue with the way I've deployed the server asynchronously, but I'm really not sure. The code for each file is below:
server.py
import socketio
from aiohttp import web
HOST = '127.0.0.1'
PORT = 10001
# create a Socket.IO server
sio = socketio.AsyncServer(async_mode='aiohttp', logger=True, engineio_logger=True)
app = web.Application()
sio.attach(app)
#sio.on('connect')
def connect(sid, environ):
print('connect ', sid)
if __name__ == '__main__':
web.run_app(app, host=HOST, port=PORT)
client.js
const io = require('socket.io-client');
const HOST = '127.0.0.1';
const PORT = '10001';
const socket = io(`http://${HOST}:${PORT}`);
console.log('Socket instantiated!');
socket.on('connect', () => {
console.log(`socket connected: ${socket.connected}`);
});
The output I would expect is to see the server print out that the client has connected, and then for the client to print out that it has connected too. However, the client never seems to receive the 'connect' event, so never prints anything to the console.
Finally, an example of the server's output is:
Server initialized for aiohttp.
======== Running on http://127.0.0.1:10001 ========
(Press CTRL+C to quit)
1c17586e4c7e49b48abefea2fba460e6: Sending packet OPEN data {'sid': '1c17586e4c7e49b48abefea2fba460e6', 'upgrades': ['websocket'], 'pingTimeout': 60000, 'pingInterval': 25000}
connect 1c17586e4c7e49b48abefea2fba460e6
1c17586e4c7e49b48abefea2fba460e6: Sending packet MESSAGE data 0
While the client's output is annoyingly just
$ node mySocket.js
Socket instantiated!
and then it just hangs doing nothing.
I'm clearly misunderstanding something here, so thank you in advance!
Small update
I quickly tested using the python socketio client, and succesfully got an actual connection, so this should narrow it down to something I've done in the JS client.
Well, I ended up downgrading from socket.io-client 3.00 (did not see there was this major release 3 days ago) back to 2.3.1, and everything started working again! However, based on the lack of issues listed on Github, I'm guessing this is not a bug that is affecting everyone.
My goals is to have real-time communication between a number of raspberry pi's over a server. I need the server for live access to logging.
I'm using the python Socket.io library from here to connect to a NodeJS Express/socket.io server. Eventually I intend to run the NodeJS server on an actual server, but I'm currently running the server and client on one raspberry pi 3.
I've managed to get the communication going in both directions, but after a few minutes of inactivity (doesn't happen when there is data flowing), the python script will log "Received unexpected packet of type 1" and completely stop working. I've tested the connection with a regular html/js client, where this did not happen.
I'm also using the background task function provided by the python socket.io library to listen for button presses through the Pi's GPIO pins.
Any idea what may be causing the process to stop? The 'disconnect' event does not fire. I've been googling the message, but haven't found anything so far, but I'm also new to Python...
I think it has to do with the multiple processes? When I comment out the start_background_task(buttons) line, this doesn't seem to happen.
Thanks!! I can't find too much more about SocketIO on client side python...
app.js (nodeJS)
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
io.on('connection', function(client) {
console.log('Client connected...');
client.on('button', function(data){
console.log(data);
});
});
server.listen(4200);
client.py
import socketio
import RPi.GPIO as GPIO
GPIO.setwarnings(False) # Ignore warning for now
GPIO.setmode(GPIO.BOARD) # Use physical pin numbering
GPIO.setup(10, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
sio = socketio.Client()
#sio.on('connect')
def on_connect():
print('connected to server')
#sio.on('disconnect')
def on_disconnect():
print('disconnected from server')
def buttons():
while True:
if GPIO.input(10) == GPIO.HIGH:
print("Button was pushed!")
sio.emit('button', {"pi":1, "button": 1})
if __name__ == '__main__':
sio.connect('http://localhost:4200')
sio.start_background_task(buttons)
EDIT: fixed duplicate function names. No change in outcome.
I have a web application and need to continuously display the actions going on in the backend on the browser. I have been trying to use socket.io in Flask. But I need to get the data to be displayed from other Python modules in my project. So, I tried to make a socket connection between Flask and the external module from which I will be getting data to be displayed on the browser(without any delay).
#socketio.on('my event')
def server(message):
s = socket.socket()
print "Socket successfully created"
port = 12345
s.bind(('', port))
print "socket binded to %s" %(port)
s.listen(5)
print "socket is listening"
while True:
c, addr = s.accept()
print 'Got connection from', addr
print c.recv(1024)
emit('my response', {'data': c.recv(1024)})
c.close()
print c.recv(1024) is printing data on the console. But the same data is not getting reflected on the browser. It's throwing this error -
error: [Errno 98] Address already in use
This means it's failing at emit after print c.recv(1024). What could be going wrong?
My first doubt is if this kind of connection is allowed. I mean, can we have a socket connection created inside socket.io in Flask?
Else, what is the best solution to display the backend actions on the browser continuously using Flask? I also have the web application with Django. Any solution for my use case with either Flask or Django will be appreciated (preferably Django).
Using the answer given by Miguel, I could find an appropriate solution. In the external script, we need to create a SocketIO object as follows:
socketio = SocketIO(message_queue='redis://')
Then I can use emit to send the data to be displayed on the front end.
def fn():
socketio.emit('my response', {'data': 'ur data goes here'})
fn()
And on the frontend,
var socket = io.connect('http://' + document.domain + ':' + location.port);
socket.on('connect', function() {
socket.on('my response', function(msg) {
$('#log').append('<p>Received: ' + msg.data + '</p>');
document.getElementById('<div_id>').innerHTML += msg.data + "<br>";
});
});
Finally, on the Flask server side, we need to create the SocketIO object as follows:
socketio = SocketIO(app, message_queue='redis://')
Then run Flask with socketio.run(app,host='<ip>',port=<port>)
The problem is that each time a client sends the event named my event to your server, you will try to start a new socket server on port 12345. Obviously this is only going to work the first time.
Have you seen the Emitting from an External Process section in the documentation?
The idea is that you can emit events to clients from any auxiliary process, which is exactly what you need. The solution involves installing a message queue (Redis, RabbitMQ), to which the Flask-SocketIO server and the external processes that need to have emit powers connect to.
How do you launch a Go script in a django app safely?
I made a go script which is self contained. I would like to be able to launch a job from a django web app (I use celery to have the job run in the background). What would be the proper/safer way of achieving this? Maybe a way to isolate this process?
I feel that running...
os.system(f"./goscript -o {option1} -b {optiom2}")
...is quite unsafe.
as a bonus, I'd like to be able to get the output to see if the script crashes etc... but that is a bonus question.
Something like this should help IMHO
import shlex
import subprocess
def get_output(command, working_folder=None):
logging.debug("Executing %s in %s", command, working_folder)
try:
output = subprocess.check_output(shlex.split(command), cwd=working_folder)
return output.decode("utf-8")
except OSError:
logging.error("Command being executed: {}".format(command))
raise
Thanks to the people who've answered. I've actually justed remembered that a much better solution would be to use an asynchronous messaging queue library. The one I'm familiar with, and this is very easy to adapt is ZMQ https://zeromq.org/. It's dead easy to do a server/client setup with the Go script listening as a server and the django app requesting as a client for a job.
As a proof of concept, here's a snippet from the documentations of the different libraries.
Server in GO
This script is the server, written in Go, I beleive it can be set as a service to run continuously, waiting for django to send a job to do.
// source: https://github.com/pebbe/zmq4/blob/master/examples/hwserver.go
//
// Hello World server.
// Binds REP socket to tcp://*:5555
// Expects "Hello" from client, replies with "World"
//
package main
import (
zmq "github.com/pebbe/zmq4"
"fmt"
"time"
)
func main() {
// Socket to talk to clients
responder, _ := zmq.NewSocket(zmq.REP)
defer responder.Close()
responder.Bind("tcp://*:5555")
for {
// Wait for next request from client
msg, _ := responder.Recv(0)
fmt.Println("Received ", msg)
// Do some 'work', can take a whilst
time.Sleep(time.Second)
// Send reply back to client
reply := "World"
responder.Send(reply, 0)
fmt.Println("Sent ", reply)
}
}
Client in python
Here is the python app that can be easilly called within any http request. It can create the zmq context and start sending stuff to do to the go server.
# source: http://zguide.zeromq.org/py:hwclient
#
# Hello World client in Python
# Connects REQ socket to tcp://localhost:5555
# Sends "Hello" to server, expects "World" back
#
import zmq
context = zmq.Context()
# Socket to talk to server
print("Connecting to hello world server…")
socket = context.socket(zmq.REQ)
socket.connect("tcp://localhost:5555")
# Do 10 requests, waiting each time for a response
for request in range(10):
print("Sending request %s …" % request)
socket.send(b"Hello")
# Get the reply.
message = socket.recv()
print("Received reply %s [ %s ]" % (request, message))
# Gracefully closing the sockects
socket.close()
context.term()
# Back to normal django stuff
What's creat with this approach is that the clieant can dynamically creat and shut down the zmq context. Furthermore, you don't even have to have the go script running on the same server. You could communicate to any IP addresses. Provided you take the care to at least encrypte the packages, o look at the security features ZMQ provides.
--
note: I know I'm answering my own question, but it's like telephoning IT, you need to phone them to solve the problem right when they pick up the phone