即时通讯-Socket.IO
Socket.IO
- Socket.IO 主要使用WebSocket协议
- !!! Socket.IO 不等价于 WebSocket,WebSocket只是Socket.IO实现即时通讯的其中一种技术依赖,而且Socket.IO还在实现WebSocket协议时做了一些调整
- 如果又特殊需求,Socket.io可以回退到几种其它方法: Adobe Flash Sockets,JSONP拉取,AJAX拉取,提供了完全相同的接口
- Socket.IO 会自动选择合适双向通信协议,我们用的时候了解套接字咋回事就OJ8K
- 但是Socket.io并不是一个基本的,独立的,能够回退到其它实时协议的WebSocket库,支持标准WebSocket的服务端不能直接连接到Socket.io服务器,并且支持Socket.io的客户端也不能与非Socket.io框架的WebSocket服务器通信
- Socket.io要求客户端与服务器端均须使用该框架
- Socket.io的在通信时是串行执行,我们使用协程来实现异步执行,处理不同的客户端
Python实现
- 客户端首发的请求,发送到
eventlet
,eventlet
通过协程调用的方式找到socket.io
安装
sudo pip install python-socketio
sudo pip install eventlet # eventlet包提供了协程的支持
服务端实现
from eventlet import monkey_patch
monkey_patch()
import eventlet.wsgi
import socketio
# 创建服务器(指定异步执行模块)
sio = socketio.Server(asyne_mode = 'eventlet')
# 创建应用
app = socketio.Middleware(sio)
ip_port = ('', 8888) # 留空默认监听0.0.0.0
# 启动服务器
socket = eventlet.listen(ip_port)
eventlet.wsgi.server(socket, app)
事件
- 在
socket.io
中没有路由的概念, 只有事件,所以我们需要监听事件,使用sio.on(event)
装饰器的方式监听事件对应的处理函数(sio是服务器对象)
- connect: 客户端一旦链接 im 服务器 就会触发, 会传进来两个参数:
sid
: 每个客户端和服务点建立连接后会生成一个唯一的会话标识
environ
: 一个字典结构,里面包含了三次握手之后,发送的一次wb协议
握手携带的信息(url, 请求头,状态行......)
- 重点 我们可以在三次握手之后发送
wb协议
的时候自定义一些请求信息(用户信息啥的),比如在headers
中或者是QueryString
中
- 因为发送
wb协议
的时候,时使用http1.1
协议进行发送的
- 在后台我们无法根据会话的sid得到是哪个用户链接的,不知道用户sid会话就无法给用户发送消息,所以可以要求前台在用户链接到im服务器的时候,在
wb协议
的的environ
中把用户的信息传过来,这样把sid 和environ
中的用户信息 暂时双向绑定
- message: 监听客户端发过来的讯息,接收两个参数
sid,
,data
其中data
中包含了发送过来的数据
- disconnect: 客户端在四次挥手结束触发,后只会传进来一个
sid
回复
- emit: # 注意 这个默认是群发,只要连接到我们服务器上且监听了message时间的客户端都会收到
- 发送消息给指定的客户端需要设置
room
参数,room就类似以前的聊天室
- 如果设置
room=sid
则该回复只会发送到该sid对应的会话,其他的会话无法收到
- 如果设置
room= room_id
那么只有进入该房间的会话才会收到消息
- 可以使用
sio.enter_room(sid, room = 'room_id')
来让指定的用户进入房间
- 使用
sio.leave_room(sid, room = 'room_id')
来让指定用户退出房间
Demo
from eventlet import monkey_patch
import eventlet.wsgi
import socketio
monkey_patch() # 对下面的操作打补丁
# 创建服务器(指定异步执行模块)
sio = socketio.Server(asyne_mode = 'eventlet')
# 创建应用
app = socketio.Middleware(sio)
# 监听事件
@sio.on('connect')
def test_connect(sid, environ):
print('{}, 建立了客户端链接'.format(sid))
print('----------------------------------------------------------------------------')
for k, v in environ.items():
print('{}: {}'.format(k, v))
# 让客户链接之后进入到指定的房间
sio.enter_room(sid, 'test_room1')
@sio.on('disconnect')
def test_disconnect(sid):
print('链接已经断开')
@sio.on('message')
def test_message(sid, data):
print('收到客户端发来的消息: {}'.format(data))
sio.emit('message', '这是服务器发送的广播') # 注意 这个默认是群发,只要连接到我们服务器上且监听了message时间的客户端都会收到
sio.emit('message', '这是服务器对指定用户发送的 消息, 使用了 room=sid', room=sid) # 支队该sid会话用户发送消息
sio.emit('message', '这是服务器对指定房间内发送的消息 room=room_id', room='test_room1') # 所有链接到这个房间的会话都会收到
@sio.on('test_leave')
def test_leave(sid,data):
sio.leave_room(sid, room='test_room1') # 谁对这个事件发送消息,谁就会退出 'test_room1' 房间
sio.emit('message', '{}已经离开房间'.format(sid), room='test_room1') # 在这个房间内向其他会话推送消息, 注意! 已经退出的不会再收到了
ip_port = ('', 8888) # 留空默认监听0.0.0.0
## 启动服务器
socket = eventlet.listen(ip_port)
eventlet.wsgi.server(socket, app)
Google插件使用教程