I am new to Python and networking. I am trying some Python code at server side to display some continous data on my client browser. I have taken this sample code from net itself. The problem is that this code works fine on local machine when i try to access it my browser using localhost but doesn't works when i try to access it from other machine. In Ubuntu i doesn't get any data on my browser but in windows i get all data pushed on my browser when i stop the server code. I am using Twisted and Flask in Python for this. Here is the code i am trying:
import random
from twisted.web.server import Site
from twisted.web.wsgi import WSGIResource
from twisted.internet import reactor
import time
from flask import Flask, request, Response
app = Flask(__name__)
def event_stream():
count = 0
while True:
count += 1
yield 'data: %d\n\n' % count
time.sleep(5)
print 'data sent...'
#app.route('/my_event_source')
def sse_request():
return Response(
event_stream(),
mimetype='text/event-stream')
#app.route('/')
def page():
return '''
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="//code.jquery.com/jquery-1.8.0.min.js"></script>
<script type="text/javascript" src="EventSource.js"></script>
<script type="text/javascript">
$(document).ready(
function() {
sse = new EventSource('/my_event_source');
sse.onmessage = function(message) {
console.log('A message has arrived!');
$('#output').append('<li>'+message.data+'</li>');
}
})
</script>
</head>
<body>
<h2>Hello World Example to implement Server Sent Event using Twisted in Python...</h2>
<ul id="output"></ul>
</body>
</html>
'''
if __name__ == '__main__':
print 'starting server...'
resource = WSGIResource(reactor, reactor.getThreadPool(), app)
site = Site(resource)
reactor.listenTCP(9999, site)
reactor.run()
Can someone help me why the data is not getting displayed when i am trying to access it from other machine (or how can i debug it). Any help is greatly appreciated.
Related
I am creating an interface for a Random Number Generator. Just using the script on my machine, it works perfectly.
But when I host the interface on a Server (IONOS VPS), it does not work properly. I can still access the interface and load the the html. Sometimes it shows one emitted number or 2 and when I still wait sometimes the interface receives another number.
In my python-console I get the periodic GET requests to /socket.io/?EIO=4&transport=polling&t=00maxxx.
This is what my Browser-network-console shows.
enter image description here
I guess that the connection never really happens completely.
I have already checked the compatibility of flask-socketio with my server.
My server code looks like this:
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
from flask_cors import CORS
import eventlet
import threading
eventlet.monkey_patch()
async_mode = None
app = Flask(__name__)
CORS(app)
socketio = SocketIO(app, async_mode='async_mode', logger=True)
# starting background thread
def background_thread():
while True:
socketio.emit('my_response',
{'data': 'Server generated event'})
# create html template
#app.route("/")
def index():
return render_template('index.html', async_mode=socketio.async_mode)
#socketio.event
def my_ping():
emit('my_pong')
<... more vent handlers etc. ...>
if __name__ == '__main__':
PORT = json.load(open('config.json'))["PORT"]
print("Running on localhost:"+str(PORT))
socketio.run(app, debug=True, host='0.0.0.0', port=PORT)
The client looks like this:
<!DOCTYPE HTML>
<html lang="en">
<head>
<!--Used character set -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Random Number Generator</title>
<script charset="utf-8" src="{{ url_for('static', filename='js/jquery.min.js') }}">
<script charset="utf-8" src="{{ url_for('static', filename='js/socket.io.js') }}"></script>
<script charset="utf-8" src="{{ url_for('static', filename='js/server.js') }}" type="text/javascript"></script>
</head>
<body>
More HTML here
</body>
</html>
My server.js looks like this
var socket = io();
$(document).ready(function() {
some code
});
// Interval function that tests message latency by sending a "ping"
// message. The server then responds with a "pong" message and the
// round trip time is measured.
var ping_pong_times = [];
var start_time;
window.setInterval(function() {
start_time = (new Date).getTime();
$('#transport').text(socket.io.engine.transport.name);
socket.emit('my_ping');
}, 1000);
// Handler for the "pong" message. When the pong is received, the
// time from the ping is stored, and the average of the last 30
// samples is average and displayed.
socket.on('my_pong', function() {
var latency = (new Date).getTime() - start_time;
ping_pong_times.push(latency);
ping_pong_times = ping_pong_times.slice(-30); // keep last 30 samples
var sum = 0;
for (var i = 0; i < ping_pong_times.length; i++)
sum += ping_pong_times[i];
$('#ping-pong').text(Math.round(10 * sum / ping_pong_times.length) / 10);
});
Anyone has an idea what the problem is?
Your connection probably never upgrades to websockets. If that's the case it stays in polling mode and will poll every 25 seconds. More info on the ping interval
However, I also see you're using eventlet and monkey patching it, but you set your async_mode to the string 'async_mode' instead of the value None you define a bit higher. I would try setting it to 'eventlet', see if that fixes it.
Like this:
import eventlet
import threading
eventlet.monkey_patch()
app = Flask(__name__)
CORS(app)
socketio = SocketIO(app, async_mode='eventlet', logger=True)
Also if you're using the development webserver, you might need to use Gunicorn. Socketio deployment with Gunicorn
I'm having trouble running Flask & SocketIO with Eventlet despite using socketio.run(), any suggestions are appreciated. I'm currently on Python 3.9 and I've tried multiple different versions of each of these modules with no avail.
[2021-04-04 06:39:05,709] WARNING in __init__: Flask-SocketIO is Running under Werkzeug, WebSocket is not available.
"GET /socket.io/?EIO=4&transport=websocket HTTP/1.1" 400 -
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SAR</title>
<script src="https://cdn.socket.io/3.1.3/socket.io.min.js" integrity="sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh" crossorigin="anonymous"></script>
</head>
<body>
<button id="ping" onclick="send()">ping</button>
<script>
var socket = io.connect("http://" + document.domain + ":" + location.port, {transports: ['websocket']});
socket.on("connect", function(){
socket.emit("ping", "Established a connection, pinging!");
});
socket.on("pong", function(response){
console.log(response)
});
function send(){
socket.emit("ping", "ping_data");
}
</script>
</body>
</html>
app.py
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
import eventlet
app = Flask(__name__)
socketio = SocketIO(app, logger=True)
#app.route( '/' )
def index():
return render_template( 'index.html')
def receivedCallback():
print('Pong received by user!')
#socketio.on( 'ping' )
def handle_ping(data):
print("received", data)
socketio.emit('pong', "pong_data", callback=receivedCallback)
if __name__ == '__main__':
socketio.run(app)
It seems like running my main file through the terminal resolves this issue. If anyone knows why this is please do share, thanks. :)
python app.py
To give a loose idea of why it runs with python app.py is that the if __name__ == '__main__' is executed only when it is run through the terminal, much like how the main function is called first in many other programming languages like Java or C when run from the terminal directly.
When a Flask app is run through Werkzeug, the flask app instance is imported and sort of wrapped into a module by Werkzeug in which the requests are routed into. (That is why the if __name__ == __main__ part is never executed – much like when you import another module in your code, the main function of that module is never called.) So, as far as my understanding goes, when you run your Flask app through Werkzeug, the requests are received and routed over HTTP by default and not over the WebSocket protocol that Flask-SocketIO uses when you run socketio.run(). The WebSocket protocol requires a socket to be always open, enabling asynchronous I/O which cannot work in HTTP as it is a client-server protocol.
I, however, do not have an answer to how to solve the problem and work with Flask-SocketIO through Werkzeug, but I hope the above explanation throws some light into your problem and drives you in the correct direction to look at.
Suppose ther is a chat group.
Is there a way to append new messages sent by any member of a particular group to the html page of all the online users in that group using FLASK.
WITHOUT: creating a thread for each users and monitoring for latest updates in the chats.
This is an example, with a very minimal code. If you are interested then you can explore more and do the experiments.
Firstly, you need the Flask-SocketIO module, run the below command to install it.
pip install flask-socketio
With this example, the project directory will be something like below:
ProjectDirectory
|
|-> templates
| |
| |-> index.html
|
|-> app.py
app.py
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'randomSecretKEy#123'
socket = SocketIO(app)
#app.route('/')
def index():
return render_template('index.html')
#socket.on('message')
def message(data):
print(data)
emit('receive_message', data, broadcast=True)
if __name__ == '__main__':
socket.run(app)
index.html
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
<script src="//code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
var socket = io();
socket.on('connect', function() {
console.log('Connected to server');
});
socket.on('receive_message', function(msg) {
console.log('Received message: ', msg)
})
function sendMessage() {
msg = $('#message').val()
socket.emit('message', msg)
}
</script>
<input type="text" id="message"><button onclick="sendMessage()">Send</button>
Run the Flask app, open two browser tabs, with web developer tools opened side by side. AS soon as you open, you will see that Connected to server message has been logged. Now, type some message and hit the send button, in one tab, and you will see that, the message has been received in another tab's console.
I hope you get a direction with this and it is helpful for you.
Note: Again, I am telling this is a very basic example. Off course, you can add more logic and functionality, and make it more like a chatting app, but it will be out of the scope of this question. So, I will leave it to you and your imagination, to which extent you can learn and take this ahead. You can read about the module's documentation here.
I am doing a very simple thing, just sending a message to my Flask app via Socket.IO . It works like a charm with English, but some other languages break somewhere in the process.
Minimal working example follows.
testapp.py:
from flask import Flask
from flask_socketio import SocketIO
app = Flask('example')
socketio = SocketIO(app)
#socketio.on('test')
def on_connect(data):
print(data)
if __name__ == '__main__':
socketio.run(app)
index.html:
<!doctype html>
<html>
<body>
<script type="text/javascript" src="js/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost:5000');
socket.on('connect', function() {
socket.emit('test', 'ASCII text');
socket.emit('test', 'Český text');
});
</script>
</body>
</html>
Instead of expected Český text, I am getting ÄŚeskĂ˝ text on the console.
I am using the newest versions of both the server packages (Flask-SocketIO 3.0.2, python-socketio 2.0.0, python-engineio 2.2.0) and the client (socket.io.js 2.1.1) and also checked that both of my files are UTF-8 encoded.
Some bug reports and questions mention a breaking change that happenned between 1.x and 2.x versions, so i tried using some older versions of the client (1.4.8, 1.7.4) instead of the newest one. The result was not much better: ÃÅeskÄË text.
This is beginners' stuff, so there must be a popular SO question covering it already. I probably just can't find it. So... what did I miss?
I'm trying to write simple web application using Tornado and JS Prototype library. So, the client can execute long running job on server. I wish, that this job runs Asynchronously - so that others clients could view page and do some stuff there.
Here's what I've got:
#!/usr/bin/env/ python
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
import os
import string
from time import sleep
from datetime import datetime
define("port", default=8888, help="run on the given port", type=int)
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render("templates/index.html", title="::Log watcher::", c_time=datetime.now())
class LongHandler(tornado.web.RequestHandler):
#tornado.web.asynchronous
def get(self):
self.wait_for_smth(callback=self.async_callback(self.on_finish))
print("Exiting from async.")
return
def wait_for_smth(self, callback):
t=0
while (t < 10):
print "Sleeping 2 second, t={0}".format(t)
sleep(2)
t += 1
callback()
def on_finish(self):
print ("inside finish")
self.write("Long running job complete")
self.finish()
def main():
tornado.options.parse_command_line()
settings = {
"static_path": os.path.join(os.path.dirname(__file__), "static"),
}
application = tornado.web.Application([
(r"/", MainHandler),
(r"/longPolling", LongHandler)
], **settings
)
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
main()
This is server part. It has main view (shows little greeting, current server time and url for ajax query, that executes long running job. If you press a button, a long running job executes. And server hangs :( I can't view no pages, while this job is running.
Here is template page:
<html>
<head>
<title>{{ title }}</title>
<script type="text/javascript" language="JavaScript" src="{{ static_url("js/prototype.js")}}"></script>
<script type='text/javascript' language='JavaScript'>
offset=0
last_read=0
function test(){
new Ajax.Request("http://172.22.22.22:8888/longPolling",
{
method:"get",
asynchronous:true,
onSuccess: function (transport){
alert(transport.responseText);
}
})
}
</script>
</head>
<body>
Current time is {{c_time}}
<br>
<input type="button" value="Test" onclick="test();"/>
</body>
</html>
what am I doing wrong? How can implement long pooling, using Tornado and Prototype (or jQuery)
PS: I have looked at Chat example, but it too complicated. Can't understand how it works :(
PSS Download full example
Tornado is single-threaded web server. Your while loop in wait_for_smith method is blocking Tornado.
You can rewrite that method like this:
def wait_for_smth(self, callback, t=10):
if t:
print "Sleeping 2 second, t=%s" % t
tornado.ioloop.IOLoop.instance().add_timeout(time.time() + 2, lambda: self.wait_for_smth(callback, t-1))
else:
callback()
You need to add import time at the top to make this work.
function test(){
new Ajax.Request("http://172.22.22.22:8888/longPolling",
{
method:"get",
asynchronous:true,
onSuccess: function (transport){
alert(transport.responseText);
}
})
}
should be
function test(){
new Ajax.Request("/longPolling",
{
method:"get",
asynchronous:true,
onSuccess: function (transport){
alert(transport.responseText);
}
})
}
I've converted Tornado's chat example to run on gevent. Take a look at the live demo here and the explanation and source code here.
It uses lightweight user-level threads (greenlets) and is comparable in speed/memory use with Tornado. However, the code is straightforward, you can call sleep() and urlopen() in your handlers without blocking the whole process and you can spawn long running jobs that do the same. Under the hood the application is asynchronous, powered by an event loop written in C (libevent).
You can read the introduction here.
I have read the book called "Building the Realtime User Experience" by Ted Roden, and it was very helpful. I have managed to create a complex realtime chat system using Tornado (python). I recommend this book to be read as well as "Foundations of Python Network Programming" by John Goerzen.