先把背景说清楚吧:
这两天要为web端做一个实时数据显示的需求。就是web端的数据通过websocket的方式来实时拉取。
结合需求研究了下,觉得socketio的比较简单,因为服务端的数据还要从其他网站抓回来,对方用的就是socketio。这玩意貌似服务端是nodejs的。我就找找有没有python版的。最后用以下这东西来做服务端。
https://pypi.python.org/pypi/python-socketio/1.6.1
数据来源也用python来做客户端抓取吧。用这个:
https://pypi.python.org/pypi/socketIO-client
工具背景介绍完了,就说下基本逻辑吧。
1.写一个程序到其他网站抓数据,拿到后放到Redis消息队列。
2.我们的web端连接到自己的socketio的服务端
3.自己的服务端从redis队列获取到数据后,直接广播给所有的web端。
抓取端的代码:
def on_message(*args):
# 框架会自动解析出dict
TickHelper.handle(args)
def on_connect():
logging.info("success connect server")
def on_disconnect():
logging.info("disconnect from server")
def on_reconnect():
logging.info("reconnect to server")
def on_emit(*args):
logging.info("success emit")
def run(host,port):
socketIO = SocketIO(host,port
, headers={'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'}
)
socketIO.on('connect', on_connect)
socketIO.on('disconnect', on_disconnect)
socketIO.on('reconnect', on_reconnect)
socketIO.emit('',on_emit)#随便提交一个啥都可以。
socketIO.on('message', on_message)
#wait forever
socketIO.wait()
下面是上文handle函数的逻辑,其实很简单,就是通过redis,送到队列里。
mgr = socketio.RedisManager('redis://xxx.xxx.xxx.xx:6379/0',write_only=True)#对于socketio来说,因为这里我没有receive需要,所以改为write_only
def handle(msg):
mgr.emit("message", msg, room='tick')#这个room的概念很不错,相当于group的情况,可以对这个room进行广播
下面就是服务端啦。
eventlet.monkey_patch()#切记要加,否则一辈子出不来数据
mgr = socketio.RedisManager('redis://xxx.xxx.xxx.xxx:6379/')#这里的redis的topickey,代码里有默认了socketio。这里可不能write_only哦。
sio = socketio.Server(async_handlers=True, logger=True,client_manager=mgr)
#通过到这里的设置,socketio则能自动接收上面抓取端推送的数据,自动推送给我们的web端了。
@sio.on('connect', namespace='/')
def connect(sid, environ):
sio.enter_room(sid=sid,room="tick")#吧客户端放到组里
logging.info("connect "+sid)
@sio.on('tick_request', namespace='/')
def message(sid):
pass
@sio.on('disconnect', namespace='/')
def disconnect(sid):
logging.info('disconnect '+sid)
if __name__ == '__main__':
init_logger()
app = socketio.Middleware(sio)
# deploy as an eventlet WSGI server
eventlet.wsgi.server(eventlet.listen(('', 8000)), app)
切记切记,eventlet框架,不能再用python自己的thread来做什么处理。否则代码都会挂在你的thread里,eventlet啥都不管了。