1.socketio和websocket 的区别
WebSocket是一种通信协议,它通过TCP连接在客户端和服务器之间提供双向通信,WebSocket连接始终保持打开状态,因此它们允许实时数据传输。当客户端向服务器触发请求时,它不会在接收到响应时关闭连接,而是会持续存在并等待客户端或服务器终止请求。
本文章介绍flask socketio 和tornado websocket使用例子
Socket.IO 是一个库,可用于在客户端和Web服务器之间进行实时和全双工通信。它使用WebSocket协议提供接口。通常,它分为两部分,WebSocket和Socket.io都是事件驱动的库.
简单说 socketio 是对websocket的封装 服务端用socketio客户端也要用socketio 服务端用websocket客户端也要用websocket
SocketIO时,不用担心兼容问题,底层会自动选用最佳的通信方式。因此说,WebSocket是SocketIO的一个子集。
broadcast 为True 进行全员广播
ws.emit('user_message', {"test_111": random.randint(1, 10), "ut": ut}, broadcast=True)
所需要的安装包
- python-engineio==3.13.1
- python-socketio==4.6.0
- Flask-SocketIO==4.3.1
- Werkzeug==1.0.1
- flask==1.0.2
客户端连接方式
- import socketio
-
- sio = socketio.Client()
- ut = "1"
-
-
- @sio.event
- def connect():
- print('connection established')
-
-
- # 监听服务端推送消息
- @sio.event
- def user_message(data):
- print('user_message received with ', data)
- # sio.emit('my response', {'response': 'my response'})
-
-
- @sio.event
- def disconnect():
- print('disconnected from server')
-
-
- # 连接服务端 IP+端口
- sio.connect('http://localhost:8091')
- print("000")
-
- # 向服务端发送消息
- sio.emit('sub_user_message', ut)
- sio.wait()
服务端起socketio方式
- # -*- coding: utf8 -*-
-
- # socketio要想与flask通信必须打补丁
-
- from gevent import monkey
-
- monkey.patch_all()
- print('monkey.patch_all()')
-
- from flask import Flask
- from werkzeug.utils import import_string
- from flask_socketio import SocketIO
- import flask_socketio as ws
- import time
-
- webapp = Flask(__name__, static_url_path='/static')
- webapp.config.from_object("config.Default") # 引入配置文件config.py 下Default 对象
-
- try:
- local_cfg = import_string('local_cfg.Config')
- webapp.config.from_object(local_cfg)
- except:
- pass
- webapp.debug = webapp.config.get("DEBUG", False)
- webapp.testing = webapp.config.get("TESTING", False)
- webapp.static_folder = webapp.config.get('STATIC_BASE', 'static')
- webapp.template_folder = webapp.config.get('TEMPLATE_BASE', './templates')
-
- REDIS_HOST = '127.0.0.1'
- REDIS_PORT = 6379
- REDIS_DB = 10
-
- SOCKETIO_MESSAGE_QUEUE = 'redis://:@%s:%d/%d' % (
- REDIS_HOST, REDIS_PORT, REDIS_DB) # 通过redis 实现socketio 与flask 进行通信 必须要打补丁
- # 无论是否是在WSAPP的环境中,
- # 都需要初始化socket_io,
- # 因为WEBAPP需要通过它和WSAPP进行通信
-
- socket_io = SocketIO(webapp, cors_allowed_origins='*', message_queue=SOCKETIO_MESSAGE_QUEUE)
-
-
- @socket_io.on('connect')
- def msg_connect():
- print("111111 connect")
- ws.emit('msg_connect', {'data': 'Connected'})
-
- ut = "1"
- if ut:
- ws.join_room('wx_scan_login.' + ut)
-
-
- @socket_io.on('sub_user_message')
- def sub_user_message(*args, **kwargs):
- """
- 用户需要登录访问加到user_message 房间判断用户登录
- :return:
- """
- print(*args)
-
- print("sub_user_message")
- ut = str(args)
-
- if ut:
- # 加入房间 房间名称 user_message.
- # 服务端对用户按要求加入不同房间 一个用户一个房间或多个用户一个房间
- ws.join_room('user_message.' + ut)
- while True:
- # 客户端向服务端推送消息 事件名称为:user_message 客户端要监听此事件
- ws.emit('user_message',
- {'data': {'status': 0, 'msg': '支付失败'}, 'command': 'pay'},
- room='user_message.' + ut)
- time.sleep(1)
- import random
- if ut == "12345": # broadcast为True,进行全员广播,调用一次全员广播一次
- ws.emit('user_message', {"test_111": random.randint(1, 10), "ut": ut}, broadcast=True)
-
-
- @socket_io.on('disconnect')
- def msg_disconnect():
- print('Client disconnected')
-
-
- socket_io.run(webapp, host='127.0.0.1', port=8091)
获取断开用户的id 可以flask 上下文设置
Tornado websocket
server
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
-
- import logging
- import tornado.web
- import tornado.websocket
- import tornado.ioloop
- import tornado.options
-
- from tornado.options import define, options
-
- define("port", default=3000, help="run on the given port", type=int)
-
-
- class Application(tornado.web.Application):
- def __init__(self):
- handlers = [(r"/", MainHandler)]
- settings = dict(debug=True)
- tornado.web.Application.__init__(self, handlers, **settings)
-
-
- class MainHandler(tornado.websocket.WebSocketHandler):
- def check_origin(self, origin):
- return True
-
- def open(self):
- logging.info("A client connected.")
-
- def on_close(self):
- logging.info("A client disconnected")
-
- def on_message(self, message):
- logging.info("message: {}".format(message))
-
-
- def main():
- tornado.options.parse_command_line()
- app = Application()
- app.listen(options.port)
- tornado.ioloop.IOLoop.instance().start()
-
-
- if __name__ == "__main__":
- main()
client
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
-
- from tornado.ioloop import IOLoop, PeriodicCallback
- from tornado import gen
- from tornado.websocket import websocket_connect
-
-
- class Client(object):
- def __init__(self, url, timeout):
- self.url = url
- self.timeout = timeout
- self.ioloop = IOLoop.instance()
- self.ws = None
- self.connect()
- PeriodicCallback(self.keep_alive, 20000).start()
- self.ioloop.start()
-
- @gen.coroutine
- def connect(self):
- print "trying to connect"
- try:
- self.ws = yield websocket_connect(self.url)
- print ""
- except Exception, e:
- print "connection error"
- else:
- print "connected"
- self.run()
-
- @gen.coroutine
- def run(self):
- while True:
- msg = yield self.ws.read_message()
- print "msg:",msg
- if msg is None:
- print "connection closed"
- self.ws = None
- break
-
- def keep_alive(self):
- if self.ws is None:
- self.connect()
- else:
- self.ws.write_message("keep alive")
-
- if __name__ == "__main__":
- client = Client("ws://localhost:8061/notify/anonymous?ut=RRYhwCzTbAi3945zsNjv", 5)