WebSocket 是 HTML5 提供的一种浏览器与服务器间进行全双工通讯的协议。依靠这种协议可以实现客户端和服务器端 ,一次握手,双向实时通信。
1. django-websocket 是旧版本的,现在已经没有人维护了。dwebsocket是新版的,推荐使用dwebsocket;
安装dwebsocket
python setup.py install
整个demo:
1.项目结构:
2.HelloWorld项目代码:
urls.py代码:
from django.conf.urls import url from django.contrib import admin import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/(?P<username>\w+)', views.gotoIndex), url(r'websocketLink/(?P<username>\w+)', views.websocketLink)# webSocket 链接 ]
views.py
# coding=utf8 from django.shortcuts import render import threading from models import Ad from dwebsocket.decorators import accept_websocket import json # from model_admin.models import MessageLog # 跳转到主页 def gotoIndex(request, username): return render(request, 'index.html', {'username': username}) # 存储连接websocket的用户 clients = {} # 记录连接人数 其实没什么卵用 = = count = 0 # 连接websocket ws://localhost:8000/websocketLink/22 # 因为 websocket 是协议 所以不能用 http或https @accept_websocket def websocketLink(request, username): '连接websocket' global count # 获取连接 if request.is_websocket: lock = threading.RLock()#rlock线程锁 try: lock.acquire()#抢占资源 s = {} # 因为同一个账号打开多个页面连接信息是不同的 if clients.get(username) != None: # 连接信息 键 连接名 值:连接保存 s[str(request.websocket)] = request.websocket # 已存在的连接信息继续增加 clients[username].update(s) else: # 人数加1 count = count + 1 # 连接信息 键 连接名 值:连接保存 s[str(request.websocket)] = request.websocket # 新增 用户 连接信息 clients[username] = s print("用户人数" + str(count)) # 监听接收客户端发送的消息 或者 客户端断开连接 sql = ("select id,code,name " "from " "prov_ad order by create_date desc limit 1" ) data_list = Ad.objects.raw(sql) datas = [] for item in data_list: datas.append({ 'id': item.id, 'name': item.name, # 区域名称 'code': item.code, # 区域编码 'long': item.long, # 经度 'lat': item.lat # 纬度 }) send(username,datas) except Exception as e: print e finally: # 通过用户名找到 连接信息 再通过 连接信息 k 找到 v (k就是连接信息) clients.get(username).pop(str(request.websocket)) #释放锁 lock.release() # 发送消息 def websocketMsg(client, msg): import json # 因为一个账号会有多个页面打开 所以连接信息需要遍历 for cli in client: 'client客户端 ,msg消息' b1 = json.dumps(msg).encode('utf-8') client[cli].send(b1) # 服务端发送消息 def send(username, title, data, url): 'username:用户名 title:消息标题 data:消息内容,消息内容:ulr' try: if clients[username]: websocketMsg(clients[username], { 'data': data}) except BaseException: pass finally: pass
index.html代码:
<!DOCTYPE html> <html> <head> {% load static %} <link rel="stylesheet" type="text/css" href="{% static 'iziToast/css/iziToast.min.css' %}"> <script type="text/javascript" src="{% static 'iziToast/js/iziToast.min.js' %}"></script> <script type="text/javascript" src="{% static 'iziToast/js/websocket.js' %}"></script> <title>django-websocket</title> <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script> <script type="text/javascript"> var websocket; var userId=$("#userId").val(); var name= '{{username}}'; var lockReconnect = false; //避免ws重复连接 var ws = null; // 判断当前浏览器是否支持WebSocket var wsUrl = "ws://localhost:9000/websocketLink/"+name; createWebSocket(wsUrl); //连接ws function createWebSocket(url) { try{ if('WebSocket' in window){ ws = new WebSocket(url); }else if('MozWebSocket' in window){ ws = new MozWebSocket(url); }else{ alert("您的浏览器不支持websocket协议,建议使用新版谷歌、火狐等浏览器,请勿使用IE10以下浏览器,360浏览器请使用极速模式,不要使用兼容模式!"); } initEventHandle(); }catch(e){ reconnect(url); console.log(e); } } function initEventHandle() { ws.onclose = function () { reconnect(wsUrl); console.log("llws连接关闭!" + new Date().toUTCString()); }; ws.onerror = function () { reconnect(wsUrl); console.log("llws连接错误!"); }; ws.onopen = function () { console.log("llws连接成功!" + new Date().toUTCString()); heartCheck.reset().start(); //心跳检测重置 }; ws.onmessage = function (event) { //如果获取到消息,心跳检测重置 console.log("llws收到消息啦:" + event.data); if (event.data != 'pong') { var obj = eval("(" + event.data + ")"); var data =JSON.parse(event.data) } heartCheck.reset().start(); //心跳检测重置 } } // 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function() { ws.close(); } function reconnect(url) { if(lockReconnect) return; lockReconnect = true; setTimeout(function () { //没连接上会一直重连,设置延迟避免请求过多 createWebSocket(url); lockReconnect = false; }, 544000); } //心跳检测 var heartCheck = { timeout: 5403000, //9分钟发一次心跳 timeoutObj: null, serverTimeoutObj: null, reset: function(){ clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function(){ var self = this; this.timeoutObj = setTimeout(function(){ //这里发送一个心跳,后端收到后,返回一个心跳消息, //onmessage拿到返回的心跳就说明连接正常 ws.send("ping"); console.log("ping!") self.serverTimeoutObj = setTimeout(function(){//如果超过一定时间还没重置,说明后端主动断开了 ws.close(); //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次 }, self.timeout) }, this.timeout) } } </script> </head> <body> <br> <input type="text" id="message" value="Hello, World!" /> <button type="button" id="send_message">发送消息</button> <button type="button" id="close_websocket">关闭websocket</button> </body> </html>
如果项目部署到nginx服务上,你的项目要用到dwebsocket服务
我使用的是nginx+uwsgi
一.首要需要启一个主服务:
配置nginx.conf、uwsgi.ini,正常启动服务就可以了。
二.还需要启动websocket服务,才能让ws://服务器ip进行通信
1.在项目对应的settings.py里添加下面配置,不然会提示报错:handshake的返回400,也就是客户端不合法
WEBSOCKET_FACTORY_CLASS="dwebsocket.backends.uwsgi.factory.uWsgiWebSocketFactory"
2.在新的uwsgi.ini文件里添加下面配置:
DJANGO_SETTINGS_MODULE=项目路径.settings
启动websocket服务
3.项目里添加的dwebsocket服务就开启了
正如图中所示:
运行效果入下: