flask-socketio-+Nginx反向代理在消息收发和提醒上在使用
配置
nginx
让socket.io 顺利走到后方,因为 这个 io只认一级目录,socket.io
1.1.1.30 :9000 转到
1.1.1.25:7005
http {# 基本HTTP服务器配置map $http_upgrade $connection_upgrade {default upgrade;'' close;}server {listen 9000; location /socket.io {proxy_http_version 1.1;proxy_buffering off;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "Upgrade";proxy_pass http://1.1.1.25:7005/socket.io;
}
其次必须让 socketio开跨域访问,因为,中间有代理。
socketio = SocketIO(app,cors_allowed_origins="*" ,message_queue= app.config['REDIS_URL'])
* 号可以是上面nginx在所在地址
最大的意外是html。
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Flask-SocketIO 示例</title><script type="text/javascript" src="/js/socket.io.min.js"></script><script type="text/javascript" charset="utf-8">var socket = io.connect('http://1.1.1.30:9000/chat' );socket.on('my event', function (data) {// console.log('服务器发送:', data);// socket.emit('mess', '用户已连接');// alert('服务器发送:');
虽然 var socket = io.connect(‘http://1.1.1.25:9000/chat’ ); 建立连接是代理在形式。但这个地址它是不直接使用的。
而是转为 1.1.1.30:9000/socket.io
访问到后 根据/chat.得到下面的处理handle
@socketio.on('mess' ,namespace='/chat')
def handle_mess(message):socketio.emit('mess', {'data': message}, namespace='/chat')
@socketio.on('message' ,namespace='/chat')
def handle_message(message):socketio.emit('message', {'data': '左右!'}, namespace='/chat')print(message+"from where......")if __name__ == '__main__':# app.run(debug=True,host="0.0.0.0",port=5005)
这样在原有点名后台基础上,加入了在线会话提醒的功能。避免 了反复刷新在架构。
给站名加入闪烁,提示刷新function blink(abc) {{$($('span:contains("'+abc+'")')[0]).fadeOut(500).fadeIn(500, blink.bind(null,abc));}}</script>
我也只是又一次瞎猫碰到了死耗子
这里没说我的问题,只是说了最后的设计。我的问题是,所有功能在一个,二级目录下。因为static是nginx的。而flask,是 /api下的。 nginx始终只有一个端口号来的。这让我想用 、/api/chat这样的结构。做为 io.connect(‘http://1.1.1.30:9000/api/chat’ ); 而这中间,隔了 ,一个nginx代理片段。一个app的跨域请求要求。
在突然两个都满足的时候。转了一圈通信建立了。
那么说会redis。 我的所有会议机,可以用websocket请求。但是,我是没有那么大需要。因为我没有回送数据的需要。 只有各点的提交信息,需要我去及时看。而不是一次刷新全部站点。
所以,我在提交数据时给,redis队列一个消息。在得到消息后,通过socketio给中央的控制。提醒收到一个新消息。
而且,在开通gevent,第一次使用 redis 做它的队列的时候要求,在app的开头加入
from gevent import monkey; monkey.patch_all()
感觉这个效果并不是太好。但是能用。
继续死守耗子洞口。
因为不太明白是否需要所有客户端都用websocket建立连接。就像开始说。只是总部建立一个。然后不知道怎么让客户发消息来。既然用到了redis。队列,就想也用,它的订阅吧。 接收订阅是个长期任务。
这是百度AI给的flask-soketio 接收redis的订阅 回答
from flask import Flask, render_template
from flask_socketio import SocketIO
import redisapp = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)@app.route('/')
def index():return render_template('index.html')def subscribe_redis(redis_host, redis_port, redis_channel):r = redis.StrictRedis(host=redis_host, port=redis_port)pubsub = r.pubsub()pubsub.subscribe(**{redis_channel: on_message})pubsub.run_in_thread(sleep_time=0.01)def on_message(message):data = message['data']socketio.emit('redis_message', data, namespace='/socketio')if __name__ == '__main__':# 启动后台任务订阅Redissocketio.start_background_task(subscribe_redis,redis_host='localhost',redis_port=6379,redis_channel='my_channel')socketio.run(app, debug=True)
确实不执行。提示socket已关闭。IO不对。然后。我一直在试。直接在python shell 中,subscribe_redis这个函数不阻塞,直接生效。 不错,好用。然而在 flask socket 包装下。一定会出错。 换来换用了一个Threading的另一个订阅方式。还是会出错,几乎一样。切换了python版本。照样。其他功能不受影响。 甚至订阅都是正常的。就是无法放在一起。
接着测试第二个方案。直接给redis中加入 flash-socketio格式的消息。 又得到AI的一个回答,说是 socketio dumps一下,消息的字典。说的没错,但是,人家大人是没有这个字典的。 我觉得经过反编码,是能找到方式的。 但是折腾了一夜。心灰了,dir(socketio)看到了。emit 、提交消息的函数。
既然整个app文件,socketip随便用,拿来发送消息就行了。于是每个点到人名的提交url中。都会发一个人名消息给中心这里。是通过websocket提交的。是即时的。
这样只有一个页面会连接到websocket 。会有消息但不是最终状态。知道一个大概。前期页面第个人名都是<a href id=“姓名”
function blink(abc) {{$(abc).fadeOut(500).fadeIn(500, blink.bind(null,abc));}}var socket = io.connect('http://1.1.1.30:9000/chat' );socket.on('mess', function(msg) {blink('#'+msg.data)})</script>
这样一个闪烁就做好了。
@app.route("/docheck/<sta>/<person>")
def check(sta,person):r=cl.sadd(f"check:{sta}",person)socketio.emit('mess', {'data': person}, namespace='/chat')
效率和优美就诞生了。