当前位置: 首页 > 面试题库 >

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

裴曜灿
2023-03-14
问题内容

我正在尝试创建一个可以从服务器向客户端发送消息的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()

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



 类似资料:
  • 问题内容: 我将实现类似于Facebook通知和此网站的内容(StackOverflow的通知会通知我们是否有人为我们的问题写评论/答案等)。请注意,用户将使用我的应用程序作为网站而不是移动应用程序。 我遇到以下获取结果的答案,但我需要推送结果而不是获取结果。 根据建议,我在实体类中创建了一个简单方法,并向其中添加了@PostPersist,但此方法不起作用,因此基于此答案,我添加了persist

  • 问题内容: 我是golang和websocket的新手。 我正在尝试编写一个websocket服务器,一旦握手完成,该服务器可以将消息主动发送到客户端。 但是我的服务器只会在收到来自客户端的请求后才将消息发送给客户端。 有谁知道如何实现此功能,或者在哪里可以找到相关的答案? 非常感谢。 源代码如下: 问题答案: 尝试打包websocket。 这是Godoc的一个简单示例:

  • 我有一个Netty客户端和一个Netty服务器,并按照主要教程后,为了有一个EchoClient/服务器,我想让它,使我的客户端发送消息到我的服务器,当他第一次连接到它。 下面是我的的方法,这些方法应该解决这个问题: 但是正如你所看到的,教程使用了一个ByteBuf和一个String似乎不起作用! 下面是我如何在我的方法中显示收到的消息: 但是当为使用并在构造函数中初始化它并发送它时,我的服务器不

  • 问题内容: 所以现在,我正在制作一个基于客户端服务器应用程序的多线程。在服务器端,我为接受的每个连接创建了一个线程。 在线程类中,我创建了一种将命令发送到客户端的方法。我只想要的是如何将参数发送到所有正在运行的客户端?为简单起见,我只想使此服务器向所有连接的客户端发送消息。 我已经阅读了这篇文章,并从此链接中找到方法。但是,当我尝试使用自己的代码时,中没有类似的方法。 好的,这是我的服务器和线程示

  • 当我提交表单时,我在浏览器控制台中看到“emit”消息,所以我知道表单提交事件正在触发,但我没有在服务器上收到测试消息。客户端或服务器端似乎什么也没发生,“socket.emit”函数似乎什么也没做。 我做错了什么?

  • 我试图将一个对象从服务器端发送到客户端,但找不到问题。以下是我在客户端遇到的错误: 下面是服务器端方法:无限循环中的separate方法只是从文件中读取,并将用户名和密码解析为ArrayList,这是服务器类中的实例变量。 以下是从服务器请求信息的客户端: 我对学习服务器套接字和套接字还不熟悉,但我在这里试图实现的是以下目标。当我在另一节课上按下按钮时,我会这样做: 几乎是一个通过服务器到clei