Socket.io in flask: Data from external source - python

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.

Related

Trouble connecting Python socketio server to node js socketio client

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.

Server wait during flask app socketIO script

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

Python: 404 Error when accessing page from localhost

I had a situation right now that is currently impeding my progress on my work.
I am trying to use Flask and Sockets together so that I can check if a certain user is connected or not before I can show a video feed on the web browser.
Here is my code below.
from flask import Flask, render_template, Response, jsonify, request
from flask_socketio import SocketIO
from camera import VideoCamera, SocketConnections
import socket
import pickle
import struct
import new_client as NC #this is a client module
app = Flask(__name__)
video_camera = None
global_frame = None
urlfor_container = ""
HOST = ''
PORT = 5000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Socket created')
s.bind((HOST, PORT))
print('Socket bind complete')
s.listen(10)
print('Socket now listening')
c = SocketConnections('127.0.0.1',5000)
c.Establish_Connection()
conn, addr = s.accept()
print('connected workstation ', addr)
data = b'' ### CHANGED
payload_size = struct.calcsize("L") ### CHANGED
# check if the connection was accepted
app.run(host='',threaded=True)
When I run this code, everything seems to be fine.
====== RESTART: C:\CENTRALIZED_SYSTEM_FILES\OpenCV Demozz\new_cam_serv.py ======
Socket created
Socket bind complete
Socket now listening
test message should print if code was accessed
connected
connected workstation ('127.0.0.1', 59283)
* Serving Flask app "new_cam_serv" (lazy loading)
* Environment: production
[31m WARNING: This is a development server. Do not use it in a production deployment.[0m
[2m Use a production WSGI server instead.[0m
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
However when I tried to access the webpage from localhost (localhost:5000/127.0.0.1:5000), I'm receiving a " 404 Page Not Found" error. I already have a templates folder along with the index.html inside the same folder where the main module is located but every time I run this code, I still receive the 404 message.
Also, I've tried using different variations for the IP address but no luck, still 404.
Any help from you guys will be greatly appreciated. Thank you.
EDIT: I've tried create an if name=="main" statement at the bottom and then inserted this code snippet inside the clause. Then I noticed that the flask server ran successfully and I was able to browse the page again, but here is the issue. after I interrupted the execution, then that is the only time my code for the socket connection got executed.
So my question now is... is it even possible for the socket and Flask to be used at the same time?
Thank you again.
I just want to provide an update that I have found a solution to this. It is indeed possible to use both socket and Flask at the same time.
I found out that the app.run() requires a valid IP address for it to work when used with socket. The IP address from the socket and the IP address from Flask need to be the same IP address or else it won't work. I found that out when I tried to debug my script and noticed that the socket and Flask on my script are referring to different IP addresses.
So, I changed:
app.run(host='',threaded=True)
to this:
app.run(host='127.0.0.1',threaded=True)
I've tried this with other IP addresses and it is working just fine.
Thank you again, everyone.

One way web socket communication?

I was reading about the Python websocket-client library and realized that, to receive data, we have to start a connection:
from websocket import create_connection
ws = create_connection("ws://echo.websocket.org/")
print "Received " + ws.recv() + "..."
What if I just need a one-way connection? Say a Python script is running on my laptop, and it periodically sends messages to a local web server.
To receive messages, the web server would have to start a connection, but starting a connection requires a URL to connect to. My Python script is not a web server, so it lacks a URL. How could the web server receive messages from the script?
I tried to let the server listen for clients to connect with it via
ws = websocket.WebSocket()
while 1:
print 'received "' + ws.recv()
However, I get an error.
in _recv
bytes = self.io_sock.recv(bufsize)
error: [Errno 107] Transport endpoint is not connected
That error output leads me to believe that the server needs to connect in order to receive.
If you would want one way connection to the server, you could just listen on plain socket or use UDP or use HTTP requests ore any other TCP protocol.

Keeping socket connection alive with Python client and Node.js server

I'm trying to combine a Node.js with Python to create a socket connection.
The problem is that I can send data, but I can't maintain the connection.
This is my server in Node.js
var net = require('net');
var HOST = '127.0.0.1';
var PORT = 1337;
net.createServer(function(sock) {
console.log('CONNECTED: ' + sock.remoteAddress +':'+ sock.remotePort);
sock.on('data', function(data) {
console.log('DATA ' + sock.remoteAddress + ': ' + data);
sock.write('You said "' + data + '"');
});
sock.on('close', function(data) {
console.log('CLOSED: ' + sock.remoteAddress +' '+ sock.remotePort);
});
}).listen(PORT, HOST);
console.log('Server listening on ' + HOST +':'+ PORT);
and this is my client side in Python
import socket
import sys
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect the socket to the port where the server is listening
server_address = ('localhost', 1337)
print >>sys.stderr, 'connecting to %s port %s' % server_address
sock.connect(server_address)
try:
# Send data
message = 'This is the message.'
print >>sys.stderr, 'sending "%s"' % message
sock.sendall(message)
finally:
print >>sys.stderr, 'closing socket'
This works great but the client disconnects right after it has sent the data.
Ultimately, I want to be able to give user-input to send data, and also receive data.
Any suggestions on how to do this would be appreciated.
I'll approach the user input scenario. As of now, your program simply runs its course and exists.
You want to be able to combine two naively blocking operations, running some sort of input loop (e.g. while True: data = input()) but handle incoming traffic as well.
The basic way to do this is to have 2 threads, one for user input and the other for socket connections in similar while True: data = socket.recv(buff) loop, but there's another catch here as you might block on a single connection -- you'll have to dedicate a thread per connection. In order to avoid this, you could use select, which maintains socket connections for you asynchronously.
If there's no user-input, than you can just use select -- that will be sufficient to handle multiple connections in a concise manner.
Either way, I suggest you take a look at some asynchronous event-driven frameworks that are select based such as asyncio and Twisted.

Categories

Resources