zoukankan      html  css  js  c++  java
  • 长短轮询

    长短轮询

    长轮询 Long polling 阶段(Comet Long polling)

    原理:服务端给每个客户端建立队列,让浏览器通过ajax向后端偷偷的发送请求,去各自对应的队列中获取数据,如果没有数据会阻塞,但是不会一直阻塞,会通过timeout参数及异常处理的方式限制阻塞事件,比如30s后返回客户端触发回调函数让浏览器再次发送请求。

    image-20211106173700423

    长轮询是对轮询的改进版,客户端发送 HTTP 给服务器之后,有没有新消息,如果没有新消息,就一直等待。直到有消息或者超时了,才会返回给客户端。消息返回后,客户端再次建立连接,如此反复。这种做法在某种程度上减小了网络带宽和 CPU 利用率等问题。

    这种方式也有一定的弊端,实时性不高。如果是高实时的系统,肯定不会采用这种办法。因为一个 GET 请求来回需要 2个 RTT,很可能在这段时间内,数据变化很大,客户端拿到的数据已经延后很多了。

    另外,网络带宽低利用率的问题也没有从根源上解决。每个 Request 都会带相同的 Header。

    对应的,Web 也有 AJAX 长轮询,也叫 XHR 长轮询。

    客户端打开一个到服务器端的 AJAX 请求,然后等待响应,服务器端需要一些特定的功能来允许请求被挂起,只要一有事件发生,服务器端就会在挂起的请求中送回响应并关闭该请求。客户端在处理完服务器返回的信息后,再次发出请求,重新建立连接,如此循环。

    img

    • 优点:减少轮询次数,低延迟,浏览器兼容性较好。
    • 缺点:服务器需要保持大量连接。
    • 相对于轮询优缺点:
    1. 消息基本没有延迟
    2. 请求次数减少了
    3. 消耗资源较少
    4. 现在web版本的qq和微信还是基于长轮询实现的(大公司web项目可能都会使用)

    基于ajax及队列自己实现简易版本的长轮询群聊功能

    django中的应用,可以有自己的urls.py,static静态文件夹,templates模版文件夹

    前端:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/js/bootstrap.min.js"></script>
    </head>
    <body>
    
    <h1>聊天室: <span id="d3">{{ name }}</span></h1>
    <div>
        <input type="text" name="content" id="d1">
        <button id="d2">发送</button>
    </div>
    <h1>聊天纪录</h1>
    <div class="record">
    
    </div>
    
    <script>
        // 朝后端发送用户消息
        $('#d2').click(function () {
            $.ajax({
                url: '/send_msg/',
                type: 'post',
                data: {
                    'content': $("#d1").val(),
                    'name': $("#d3").text(),
                    'csrfmiddlewaretoken': '{{ csrf_token }}'
                },
                {#dataType:"JSON",#}
                success: function (args) {
    
                }
            })
        });
    
        // 书写偷偷跟服务端要数据的代码
        function getMsg() {
            $.ajax({
                url: '/get_msg/',
                type: 'get',
                data: {'name': '{{ name }}'},
                {#dataType:"JSON",#}
                success: function (args) {
                    if (args.status) {
                        // 有消息 应该DOM操作渲染到页面上
                        // 1 创建标签
                        var pEle = $('<p>');
                        // 2 给标签添加文本内容
                        pEle.text(args.msg.name +" : "+ args.msg.content);
                        // 3 添加到div中
                        $('.record').append(pEle)
                    } else {
                        // 没有则继续发送
                    }
                    getMsg()
                }
            })
        }
    
        // 页面加载完毕之后自动触发getMsg函数的执行
        $(function () {  // 等待页面加载完毕之后自动调用getMsg函数
            getMsg()
        })
    </script>
    
    </body>
    </html>
    

    后端:

    from django.shortcuts import render
    
    # Create your views here.
    from django.shortcuts import render,HttpResponse
    import queue
    
    # Create your views here.
    
    
    
    # 全局定义一个字典用来存储客户端浏览器与队列关系
    q_dict = {}
    
    
    
    def home(request, *args, **kwargs):
        # 获取用户唯一标识
        name = request.GET.get('name')
        # 给每个客户端浏览器创建独有的队列
        q_dict[name] = queue.Queue()
        return render(request,'index.html',locals())
    
    
    def send_msg(request, *args, **kwargs):
        if request.method == 'POST':
            con = request.POST.get('content')
            name = request.POST.get('name')
            # 将该消息往所有的群聊的客户端队列中添加
            content = {'name': name, 'content': con, }
            for q in q_dict.values():
                q.put(content)
            return HttpResponse('OK')
    
    import json
    from django.http import JsonResponse
    def get_msg(request, *args, **kwargs):
        name = request.GET.get("name")
        # 去对应的队列中获取数据
        q = q_dict.get(name)
        back_dic = {'status':True,'msg':''}
        try:
            data = q.get(timeout=10)  # 等10s
            back_dic['msg'] = data
        except queue.Empty as e:
            back_dic['status'] = False
        # return HttpResponse(json.dumps(back_dic))
        return JsonResponse(back_dic)
    # 大公司一般情况下都会使用上面长轮询的方式,因为兼容性好
    

    image-20210821154018941

  • 相关阅读:
    图片一句话木马简单制作方法
    kali各工具使用介绍
    隐写工具zsteg安装及使用教程
    内网渗透中mimikatz的使用
    kali meterpreter中mimikatz模块获取密码
    一个恐怖份子上传了这张照片到社交网络。里面藏了什么信息?
    攻防世界MISC进阶之签到题
    EMC存储重装系统分区丢失恢复方法
    服务器数据迁移方法
    教您分辨U盘不能识别是哪儿坏了
  • 原文地址:https://www.cnblogs.com/randysun/p/15517839.html
Copyright © 2011-2022 走看看