簡介
Socket.IO 本是一個面向實時 web 應用的 JavaScript 庫,現在已成為擁有眾多語言支持的Web即時通訊應用的框架。
Socket.IO主要使用WebSocket協議。但是如果需要的話,Socket.io可以回退到幾種其它方法,例如Adobe Flash Sockets,JSONP拉取,或是傳統的AJAX拉取,並且在同時提供完全相同的接口。盡管它可以被用作WebSocket的包裝庫,它還是提供了許多其它功能,比如廣播至多個套接字,存儲與不同客戶有關的數據,和異步IO操作。
Socket.IO 不等價於 WebSocket,WebSocket只是Socket.IO實現即時通訊的其中一種技術依賴,而且Socket.IO還在實現WebSocket協議時做了一些調整。
優點:
- Socket.IO 會自動選擇合適雙向通信協議,僅僅需要程序員對套接字的概念有所了解。
- 有Python庫的實現,可以在Python實現的Web應用中去實現IM后台服務,通過定義事件完成和前台通訊。
缺點:
Socket.io並不是一個基本的、獨立的、能夠回退到其它實時協議的WebSocket庫,它實際上是一個依賴於其它實時傳輸協議的自定義實時傳輸協議的實現。該協議的協商部分使得支持標准WebSocket的客戶端不能直接連接到Socket.io服務器,並且支持Socket.io的客戶端也不能與非Socket.io框架的WebSocket或Comet服務器通信。因而,Socket.io要求客戶端與服務器端均須使用該框架。
Python服務器端開發
文檔
https://python-socketio.readthedocs.io/en/latest/server.html
安裝
pip install python-socketio
創建服務器
方式1
使用多進程多線程模式的WSGI服務器對接(如uWSGI、gunicorn)
import socketio
# create a Socket.IO servers
sio = socketio.Server()
# 打包成WSGI應用,可以使用WSGI服務器托管運行
app = socketio.WSGIApp(sio) # Flask Django
創建好app對象后,使用uWSGI、或gunicorn服務器運行此對象。
方式2
作為Flask、Django 應用中的一部分
from wsgi import app # a Flask, Django, etc. application
import socketio
# create a Socket.IO server
sio = socketio.Server()
app = socketio.WSGIApp(sio, app)
創建好app對象后,使用uWSGI、或gunicorn服務器運行此對象。
方式3
使用協程的方式運行 (推薦)
import eventlet
eventlet.monkey_patch()
import socketio
import eventlet.wsgi
sio = socketio.Server(async_mode='eventlet') # 指明在evenlet模式下
app = socketio.Middleware(sio)
eventlet.wsgi.server(eventlet.listen(('', 8000)), app)
說明
因為服務器與客戶端進行即時通信時,會盡可能的使用長連接,所以若服務器采用多進程或多線程方式運行,受限於服務器能創建的進程或線程數,能夠支持的並發連接客戶端不會很高,也就是服務器性能有限。采用協程方式運行服務器,可以提升即時通信服務器的性能。
事件處理
不同於HTTP服務的編寫方式,SocketIO服務編寫不再以請求Request和響應Response來處理,而是對收發的數據以消息(message)來對待,收發的不同類別的消息數據又以事件(event)來區分。
原本HTTP服務編寫中處理請求、構造響應的視圖處理函數在SocketIO服務中改為編寫收發不同事件的事件處理函數。
1)事件處理方法
編寫事件處理方法,可以接收指定的事件消息數據,並在處理方法中對消息數據進行處理。
@sio.on('connect')
def on_connect(sid, environ):
"""
與客戶端建立好連接后被執行
:param sid: string sid是socketio為當前連接客戶端生成的識別id
:param environ: dict 在連接握手時客戶端發送的握手數據(HTTP報文解析之后的字典)
"""
pass
@sio.on('disconnect')
def on_disconnect(sid):
"""
與客戶端斷開連接后被執行
:param sid: string sid是斷開連接的客戶端id
"""
pass
# 以字符串的形式表示一個自定義事件,事件的定義由前后端約定
@sio.on('my custom event')
def my_custom_event(sid, data):
"""
自定義事件消息的處理方法
:param sid: string sid是發送此事件消息的客戶端id
:param data: data是客戶端發送的消息數據
"""
pass
注意
connect 為特殊事件,當客戶端連接后自動執行
disconnect 為特殊事件,當客戶端斷開連接后自動執行
connect、disconnect與自定義事件處理方法的函數傳入參數不同
前端傳遞參數時,可以通過請求參數或者放到headers中
2)發送事件消息
群發
sio.emit('my event', {'data': 'foobar'})
給指定用戶發送
sio.emit('my event', {'data': 'foobar'}, room=user_sid)
給一組用戶發送
SocketIO提供了房間(room)來為客戶端分組
sio.enter_room(sid, room_name)
# 將連接的客戶端添加到一個room
@sio.on('chat')
def begin_chat(sid):
sio.enter_room(sid, 'chat_users')
注意:當客戶端連接后,socketio會自動將客戶端添加到以此客戶端sid為名的room中
# 將客戶端從一個room中移除
sio.leave_room(sid, room_name)
@sio.on('exit_chat')
def exit_chat(sid):
sio.leave_room(sid, 'chat_users')
# 查詢sid客戶端所在的所有房間
sio.rooms(sid)
# 給一組用戶發送消息的示例
@sio.on('my message')
def message(sid, data):
sio.emit('my reply', data, room='chat_users')
# 也可在群組發消息時跳過指定客戶端
@sio.on('my message')
def message(sid, data):
sio.emit('my reply', data, room='chat_users', skip_sid=sid)
使用send發送message事件消息
對於'message'事件,可以使用send方法
sio.send({'data': 'foobar'})
sio.send({'data': 'foobar'}, room=user_sid)
Python客戶端
import socketio
sio = socketio.Client()
@sio.on('connect')
def on_connect():
pass
@sio.on('event')
def on_event(data):
pass
sio.connect('http://10.211.55.7:8000')
sio.wait()
firecmap測試socketio接口


