python websocket Django 实时消息推送

   WebSocket 是什么?

WebSocket 是 HTML5 提供的一种浏览器与服务器间进行全双工通讯的协议。依靠这种协议可以实现客户端和服务器端 ,一次握手,双向实时通信。

 

1. django-websocket 是旧版本的,现在已经没有人维护了。dwebsocket是新版的,推荐使用dwebsocket;

安装dwebsocket

 python setup.py install

整个demo:

1.项目结构:

python websocket Django 实时消息推送

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服务上,你的项目要用到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服务就开启了

正如图中所示:

python websocket Django 实时消息推送

运行效果入下:

python websocket Django 实时消息推送

python websocket Django 实时消息推送

 

上一篇:2019.12.11 java方法(类似功能、函数)


下一篇:workman 搭建tcp服务器,和websocket互相通信