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
  • 相关阅读:
    Max Sum Plus Plus HDU
    Monkey and Banana HDU
    Ignatius and the Princess IV HDU
    Extended Traffic LightOJ
    Tram POJ
    Common Subsequence HDU
    最大连续子序列 HDU
    Max Sum HDU
    畅通工程再续
    River Hopscotch POJ
  • 原文地址:https://www.cnblogs.com/godlover/p/14478655.html
Copyright © 2011-2022 走看看