zoukankan      html  css  js  c++  java
  • 基于websocket的网页实时消息推送与在线聊天(上篇)


    基于websocket的网页实时消息推送与在线聊天(上篇)

    “使用dwebsocket在django中实现websocket”

    websocket原理图

    django框架并没有自带websocket通信,所以一般由channels或dwebsocket来实现

    一.使用dwebsocket来完成实时消息推送
    pip install dwebsocket
    

    ​ 服务端

    ​ 客户端

    代码如下

    views.py文件中

    from django.shortcuts import render,HttpResponse #引入HttpResponse
    from dwebsocket.decorators import accept_websocket #引入dwbsocket的accept_websocket装饰器
    
    def to_sendmsg(request):
        return render(request,'sendmsg.html')
    
    def to_recmsg(request):
        return render(request,'recmsg.html')
    
    clients={} #创建客户端列表,存储所有在线客户端
    
    # 允许接受ws请求
    @accept_websocket
    def link(request):
        # 判断是不是ws请求
        if request.is_websocket():
            userid=str(uuid.uuid1())
            # 判断是否有客户端发来消息,若有则进行处理,若发来“test”表示客户端与服务器建立链接成功
            while True:
                message=request.websocket.wait()
                if not message:
                    break
                else:
                    print("客户端链接成功:"+str(message, encoding = "utf-8"))
                    #保存客户端的ws对象,以便给客户端发送消息,每个客户端分配一个唯一标识
                    clients[userid]=request.websocket
                    
    def send(request):
        # 获取消息
        msg=request.POST.get("msg")
        # 获取到当前所有在线客户端,即clients
        # 遍历给所有客户端推送消息
        for client in clients:
            clients[client].send(msg.encode('utf-8'))
        return HttpResponse({"msg":"success"})
    

    urls.py

    from django.contrib import admin
    from django.urls import path
    import app.views as views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('link/', views.link),
        path('send/', views.send),
        path('to_sendmsg/', views.to_recmsg),
        path('to_recmsg/', views.to_sendmsg),
    ]
    

    recmsg.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>实时消息接收</title>
    </head>
    <body>
    <script>
        window.onload = function () {
            //先判断浏览器是否支持websocket
            if ("WebSocket" in window) {
                alert("您的浏览器支持 WebSocket!");
                // 打开一个 web socket
                ws = new WebSocket("ws://127.0.0.1:8000/link/");
                ws.onopen = function () {
                    // Web Socket 已连接上,使用 send() 方法尝试发送数据
                    ws.send("test");
                };
                //监听服务端是否有消息发送过来,当有消息时执行方法
                ws.onmessage = function (evt) {
                    //获取服务器发来的消息
                    var received_msg = evt.data;
                    //显示消息
                    alert("收到消息:"+received_msg)
                };
                //关闭页面或其他行为导致与服务器断开链接是执行
                ws.onclose = function () {
                    // 关闭 websocket
                    alert("连接已关闭...");
                };
            } else {
                // 浏览器不支持 WebSocket
                alert("您的浏览器不支持 WebSocket!");
            }
        }
    </script>
    </body>
    </html>
    

    sendmsg.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    </head>
    <body>
        <input id="msg" placeholder="输入要推送的消息">
        <button onclick="javascript:sendmsg()">推送</button>
    <script>
        function sendmsg() {
            $.post("/send/",{msg:$("#msg").val()},function (result) {
                if(result.msg=="success"){
                    alert("消息推送成功")
                }
            })
        }
    </script>
    </body>
    </html>
    
    二.使用dwebsocket来完成聊天室
    界面设计

    实现的逻辑顺序和思路:

    1.加载页面的同时连接服务器

    2.服务器监听客户端链接,当有客户端链接时,将其添加到在线列表,将在线列表和为其分配的客户端随机id发送给当前链接的客户端,并将列表发送给所有在线客户端

    3.获取服务端返回的随机客户端id和在线用户列表

    4.加载用户列表和本人id

    5.填写消息,选择群组或者指定用户,发送到后台

    6.后台服务器判断是群组消息还是私聊消息,根据不同的情况发送给指定客户端

    7.指定客户端接收到消息,显示在消息列表中

    8.离线时,服务器删除指定用户,更新在线列表,并将列表发送给所有在线客户端

    代码实现

    views.py

    #聊天界面
    def to_chat(request):
        return render(request,'chat.html')
    
    # 服务器方法,允许接受ws请求
    @accept_websocket
    def chat(request):
        # 判断是不是ws请求
        if request.is_websocket():
            # 保存客户端的ws对象,以便给客户端发送消息,每个客户端分配一个唯一标识
            userid=str(uuid.uuid1())[:8]
            clients[userid] = request.websocket
            # 判断是否有客户端发来消息,若有则进行处理,表示客户端与服务器建立链接成功
            while True:
                '''获取消息,线程会阻塞,
                他会等待客户端发来下一条消息,直到关闭后才会返回,当关闭时返回None'''
                message=request.websocket.wait()
                if not message:
                    break
                else:
                    msg=str(message, encoding = "utf-8")
                    print(msg)
                    #1、发来test表示链接成功
                    if msg == "test":
                        print("客户端链接成功:"+userid)
                        #第一次进入,返回在线列表和他的id
                        request.websocket.send(json.dumps({"type":0,"userlist":list(clients.keys()),"userid":userid}).encode("'utf-8'"))
                        #更新所有人的userlist
                        for client in clients:
                            clients[client].send(json.dumps({"type":0,"userlist":list(clients.keys()),"user":None}).encode("'utf-8'"))
        #客户端关闭后从列表删除
        if userid in clients:
            del clients[userid]
            print(userid + "离线")
            # 更新所有人的userlist
            for client in clients:
                clients[client].send(
                    json.dumps({"type": 0, "userlist": list(clients.keys()), "user": None}).encode("'utf-8'"))
    
    #消息发送方法
    def msg_send(request):
        msg = request.POST.get("txt")
        useridto = request.POST.get("userto")
        useridfrom = request.POST.get("userfrom")
        type=request.POST.get("type")
        #发来{type:"2",msg:data,user:user},表示发送聊天信息,user为空表示群组消息,不为空表示要发送至的用户
        if type == "1":
            #群发
            for client in clients:
                clients[client].send(json.dumps({"type": 1, "data": {"msg": msg, "user": useridfrom}}).encode('utf-8'))
        else:
            # 私聊,对方显示
            clients[useridto].send(json.dumps({"type": 1, "data": {"msg": msg, "user": useridfrom}}).encode('utf-8'))
            # 私聊,自己显示
            clients[useridfrom].send(json.dumps({"type": 1, "data": {"msg": msg, "user": useridfrom}}).encode('utf-8'))
        return HttpResponse(json.dumps({"msg":"success"}))
    
    

    urls.py

        # 聊天
        path('to_chat/', views.to_chat),
        path('chat/', views.chat),
        path('msg_send/', views.msg_send),
    
    

    chat.html

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap.css" rel="stylesheet">
        <link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            td {
                border: 1px #000 solid;
                margin: 0;
            }
    
            textarea {
                 100%;
                height: 100%;
            }
        </style>
    </head>
    <body style="padding: 30px">
    <span id="userid">我的随机账号:</span>
    <table>
        <tr>
            <td style=" 500px;">
                <div id="historymsg" style="height: 400px;overflow: auto"></div>
            </td>
            <td style=" 400px">
                <div id="userlist" style="height: 400px;overflow: auto"></div>
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <textarea id="msg"></textarea>
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <select class="form-control" id="isgroup">
                </select>
                <input class="btn btn-info btn-block" type="button" onclick="send()" value="发送">
            </td>
        </tr>
    </table>
    <!--脚本开始-->
    <script>
    	var ws,myid;
        window.onload = function () {
            //先判断浏览器是否支持websocket
            if ("WebSocket" in window) {
                // 打开一个 web socket,链接服务器
                ws = new WebSocket("ws://127.0.0.1:8000/chat/");
                ws.onopen = function () {
                    // Web Socket 已连接上,使用 send() 方法尝试发送数据
                    ws.send("test");
                };
                //监听服务端是否有消息发送过来,当有消息时执行方法
                ws.onmessage = function (evt) {
                    //获取服务器发来的消息
                    var received_msg = evt.data;
                    //判断是返回的是消息还是用户列表和id,1是消息,0是用户列表和id
                    msg = eval("(" + received_msg + ")")
                    //用户列表和id
                    if (msg.type == 0) {
                        //userid为空表示更新用户列表,不需要更新自己的id,否则为初次登录
                        if (msg.userid != null) {
                            myid = msg.userid
                            $("#userid").append(myid)
                        }
                        //当收到新的用户列表时,清空原来的用户列表,清空原来的用户选择框,添加群组发送选项
                        $("#userlist").empty()
                        $("#isgroup").empty()
                        $("#isgroup").append("<option value='1'>群发(或选择要私聊的用户)</option>")
                        for (var i = 0; i < msg.userlist.length; i++) {
                            //填充用户列表
                            $("#userlist").append(msg.userlist[i] + "<hr />")
                            //填充用户选择框
                            $("#isgroup").append("<option value='" + msg.userlist[i] + "'>" + msg.userlist[i] + "</option>")
                        }
                    }
                    //用户发送的消息
                    else {
                        var myDate = new Date();
                        nowtime = myDate.toLocaleString(); //获取日期与时间
                        newmsg = ""
                        //判断是自己的消息,绿色显示
                        if (myid == msg.data.user) {
                            newmsg = "<span style='color:blue'>" + msg.data.user + ":" + nowtime + "<br />" + msg.data.msg + "</span>" + "<br />"
                        } else {
                            newmsg = "<span >" + msg.data.user + ":" + nowtime + "<br />" + msg.data.msg + "</span>" + "<br />"
                        }
                        $("#historymsg").append(
                            newmsg
                        )
                    }
                };
                //关闭页面或其他行为导致与服务器断开链接是执行
                ws.onclose = function () {
                    // 关闭 websocket
                    alert("连接已关闭...");
                };
            } else {
                // 浏览器不支持 WebSocket
                alert("您的浏览器不支持 WebSocket!");
            }
        }
    	//消息发送
        function send() {
            msgtxt = $("#msg").val()
            msguser = $("#isgroup").val()
            //判断是否是群发0是,不是0 则是私聊
            if ($("#isgroup").val() == "1") {
                msg = {
                    type: "1",
                    txt: msgtxt,
                    userfrom: myid
                }
            } else {
                msg = {
                    type: "0",
                    txt: msgtxt,
                    userto: msguser,
                    userfrom: myid
                }
            }
            //发送消息后清空消息框,并定位到消息框内
            $.post("/msg_send/", msg, function () {
                $("#msg").val("")
                $("#msg").focus()
            })
        }
    
    
    </script>
    
    <!--脚本结束-->
    </body>
    </html>
    
    
    群发效果

    私聊效果


    (PS:支持原创) 转载自:https://blog.csdn.net/u012751272/article/details/89197325
    在原创基础上进行修改代码,代码链接:https://gitee.com/godlover/websocket-easy-project.git
  • 相关阅读:
    堆和栈的区别
    九度OJ 1108 堆栈的使用
    九度OJ 1201 二叉排序树
    jQuery笔记——基础知识
    JavaScript笔记——事件
    一些知识
    JavaScript笔记——BOM的操作和浏览器的检测
    JavaScript笔记——面向对象与原型
    JavaScript笔记——基础知识(二)
    JavaScript笔记——正则表达式
  • 原文地址:https://www.cnblogs.com/godlover/p/14478655.html
Copyright © 2011-2022 走看看