如何使用Flask-Socket IO从服务器向客户端发送消息

我正在尝试创建一个可以从服务器向客户端发送消息的python应用程序。目前,我正在从这里使用此示例代码。这是一个聊天应用程序,并且运行良好。我试图修改该应用程序,并在服务器端python代码中添加了一个新功能,该功能将在客户端打印一条消息“ Dummy”,但似乎不起作用。

这是我的html代码:

index.html

<body>

<ul id="messages"></ul>

<ul id="output"></ul>

<form action="">

<input id="m" autocomplete="off" /><button>Send</button>

</form>

<script src="{{url_for('static', filename='assets/vendor/socket.io.min.js')}}"></script>

<script src="{{url_for('static', filename='assets/vendor/jquery.js')}}"></script>

<script>

var socket = io.connect('http://127.0.0.1:5000/chat');

$('form').submit(function(){

socket.emit('chat message', $('#m').val());

$('#m').val('');

return false;

});

socket.on('chat message', function(msg){

$('#messages').html($('<li>').text(msg));

});

socket.on('output', function(msg){

alert(msg)

$('#messages').html($('<li>').text(msg));

});

</script>

这是我的后端代码:

web_app.py

from flask import Flask

from flask import render_template

from flask_socketio import SocketIO

from flask_socketio import emit

app = Flask(__name__)

app.config['SECRET_KEY'] = 'secret!'

socketio = SocketIO(app)

connected = False

def socket_onload(json):

socketio.emit('output', str(json), namespace='/chat')

print('received message: ' + str(json))

@socketio.on('chat message', namespace='/chat')

def handle_chat_message(json):

print('received message: ' + str(json))

emit('chat message', str(json), broadcast=True)

@socketio.on('connect') # global namespace

def handle_connect():

global connected

connected = True

print('Client connected')

@socketio.on('connect', namespace='/chat')

def handle_chat_connect():

print('Client connected to chat namespace')

emit('chat message', 'welcome!')

@socketio.on('disconnect', namespace='/chat')

def test_disconnect():

print('Client disconnected')

@app.route('/')

def index():

return render_template('index.html')

@app.route('/blah/')

def blah():

return render_template('blah.html')

main.py

import web_app

import threading

import time

def main():

import web_app

webapp_thread = threading.Thread(target=run_web_app)

webapp_thread.start()

# webapp_thread = threading.Thread(target=run_web_app, args=(i,))

while web_app.connected==False:

print "waiting for client to connect"

time.sleep(1)

pass

print "Connected..."

time.sleep(3)

print "Trying to print dummy message..."

web_app.socket_onload("Dummy")

def run_web_app():

web_app.socketio.run(web_app.app)

if __name__ == '__main__':

main()

我可以在终端中看到“收到的消息:虚拟消息”,但Web浏览器上没有任何变化。

回答:

首先,你要尝试从套接字上下文外部发出一个带有socket.io的事件。

当一个函数用@socketio.on装饰器包装时,它变成一个Event-Handlers。在服务器端触发事件时,它将搜索正确的处理程序以处理该事件,并将上下文初始化为发出该事件的特定客户端。

如果不初始化此上下文,则你socketio.emit('output', str(json), namespace='/chat')将无能为力,因为服务器不知道应向谁发回响应。

无论如何,有一个小技巧可以手动将事件发送给特定的客户端(即使你不在上下文中)。每次打开套接字时,服务器会将其分配给一个与套接字ID(sid)同名的“私有”房间。因此,为了从客户端上下文向外部客户端发送消息,你可以创建已连接客户端ID的列表,并使用room=<id>参数调用发出函数。

例如:

web_app.py:

...

from flask import Flask, request

clients = []

@socketio.on('connect')

def handle_connect():

print('Client connected')

clients.append(request.sid)

@socketio.on('disconnect')

def handle_disconnect():

print('Client disconnected')

clients.remove(request.sid)

def send_message(client_id, data):

socketio.emit('output', data, room=client_id)

print('sending message "{}" to client "{}".'.format(data, client_id))

...

然后,你可能会使用它,如下所示:

main.py:

import web_app

import threading

import time

def main():

webapp_thread = threading.Thread(target=run_web_app)

webapp_thread.start()

while not web_app.clients:

print "waiting for client to connect"

time.sleep(1)

print "Connected..."

time.sleep(3)

print "Trying to print dummy message..."

web_app.send_message(web_app.clients[0], "Dummy")

...

但是,即使你尝试执行此操作,也不会起作用(这使我们犯了第二个错误)。

其次,你将eventlet与常规Python线程混合使用,这不是一个好主意。eventlet使用的绿色线程不适用于常规线程。相反,你应该使用绿色线程来满足所有线程需求。

我在互联网上找到的一种选择是猴子修补Python标准库,以便将线程,套接字等替换为对eventlet友好的版本。你可以在main.py脚本的最顶部执行此操作:

import eventlet

eventlet.monkey_patch()

之后,它应该可以正常工作(我自己尝试了)。让我知道你是否还有其他问题…

以上是 如何使用Flask-Socket IO从服务器向客户端发送消息 的全部内容, 来源链接: utcz.com/qa/434455.html

回到顶部