• Gevent的长轮询实现方法详解


     

       长轮询

      1.浏览网页时,浏览器会传HTTP 请求到服务器,服务器会根据请求将网页的内容传给浏览器,但是在很多的情况下,使用者会需要看到最新的即时性资讯,例如观看股票市场行情,而在以前只能靠着重新载入网页才能获得最新信息,但是这样不但很浪费时间,也会佔用很多不必要的网络资源,并不是一个好的方式;

      2.长轮询就是解决这个问题的一个办法。

      什么是长轮询

      1.长时间轮询(long-polling)是让服务器在接收到浏览器发出的HTTP 请求后,服务器会等待一段时间,若在这段时间里面伺服器有新的数据更新,它就会把最新的数据传给浏览器,如果等待的时间到了之后也没有新资料的话,就会送一个回应给浏览器,告知浏览器资料没有更新;

      2.长时间轮询可以减少产生轮询(polling)造成网路频宽浪费的状况。

      浏览器如何长轮询

      浏览器向服务器发送Ajax请求,当接收到服务器响应后,需要向服务求发送新的请求。

      服务器如何处理长轮询

      1.服务器端要能够一直保持住客户端的请求,直到有响应消息;同时服务器对请求的处理要支持非阻塞模式;

      2.需要使用Eventpython内置Event是阻塞的,gevent的却是非阻塞的。

      设计场景

      1.浏览器请求获取当前的字符信息,并显示;

      2.服务器后天接受某个请求以产生随机字符并存储下来,同时推送给浏览器。

      涉及问题

      1.服务器需知道浏览器获取信息的标识来推送最新的信息;

      2.当浏览器请求更新信息时,服务器可通过Event来保留当前信息,当有新信息来的时候,重设Event来唤醒之前的处理。

      实践

      html代码

    <!doctype html>

    <html>

    <head>

        <title>Long Pooling</title>

        <style>

            #main {

              position: absolute;

              bottom: 50px;

              left: 200px;

            }

            #state{

                float:right;

                400px;

            }

        </style>

    <head>

    <body>

        <div id="main">

            <div id="inbox"></div>

        </div>

        <div id="state"></div>

        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

        <script type="text/javascript" charset="utf-8">

        var id = null;

     

        function longPolling() {

            $.ajax({

                url: "update",

                data: {"id": id},

                type: "POST",

                error: function (XMLHttpRequest, textStatus, errorThrown) {

                    $("#state").append("[state: " + textStatus + ", error: " + errorThrown + " ]<br/>");

                },

                success: function (result, textStatus) {

                    console.log(result)

                    msg_data = eval("(" + result + ")");

                    $("#inbox").append(msg_data.html);

                    id = msg_data.id;

                    console.log(msg_data)

                    $("#message").val("");

                    $("#state").append("[state: " + textStatus + " ]<br/>");

                },

                complete: longPolling

            });

        }

     

        function sendNewMessage() {

            $.ajax({

                type: "POST",

                url: "new",

            });

        }

     

        $(function(){

            longPolling();

        })

        </script>

    </body>

    </html>

     

    test.py

     

    from gevent.pywsgi import WSGIServer

    from gevent.event import Event

    from cgi import escape

    import uuid

    import urlparse

    import string

    import random

     

    def get_request_data(field, env):

        try:

            request_body_size = int(env.get('CONTENT_LENGTH', 0))

        except (ValueError):

            request_body_size = 0

        request_body = env['wsgi.input'].read(request_body_size)

        d = urlparse.parse_qs(request_body)

        data = d.get(field, [''])[0]

        return data

     

    def generate_response_data(response_body, start_response):

        response_headers = [('Content-Type', 'text/html'), ('Content-Length', str(len(response_body)))]

        start_response('200 OK', response_headers)

        return [response_body]

     

    def generate_json_data(msg_list):

        msg_dict = {}

        msg_dict["html"] = ""

        for msg in msg_list:

            msg_dict["html"] += "<div>{0}</div>".format(msg["msg"])

        msg_dict["id"] = msg_list[-1]["id"]

        res =  str(msg_dict)

        return res

     

    def id_generator(size=6, chars=string.ascii_uppercase + string.digits):

        return ''.join(random.choice(chars) for _ in range(size))

     

    file = open('longpooling.html')

    chat_html = file.read()

     

    class MessgaeBuffer(object):

        def __init__(self):

            self.cache = []

            self.message_event = Event()

        def empty(self):

            return len(self.cache) == 0

     

    def application(env, start_response):

        env_val = env['PATH_INFO']

        if env_val == "/create":

            msg_item = {}

            msg_item["id"] = str(uuid.uuid4())

            msg_item["msg"] = id_generator()

            print "create msg %s" % str(msg_item)

     

            msgBuffer.cache.append(msg_item)

            msgBuffer.message_event.set()

            msgBuffer.message_event.clear()

     

            return generate_response_data("", start_response)

        elif env_val == "/update":

            lastid = escape(get_request_data("id", env))

            if msgBuffer.empty() or msgBuffer.cache[-1]["id"] == lastid:

                msgBuffer.message_event.wait()

            for index,m in enumerate(msgBuffer.cache):

                if m["id"] == lastid:

                    return generate_response_data(generate_json_data(msgBuffer.cache[index+1:])

                                                  , start_response)

            return generate_response_data(generate_json_data(msgBuffer.cache), start_response)

        else:

            return generate_response_data(chat_html, start_response)

     

    msgBuffer = MessgaeBuffer()

     

    WSGIServer(('localhost', 8080), application).serve_forever()

     

    原文链接:http://www.maiziedu.com/wiki/frame/polling/

  • 相关阅读:
    《数据库系统概论》 -- 3.2. 视图
    Uncaught SecurityError: Failed to execute 'replaceState' on 'History': A history state object with
    在node.js中使用mongose模块
    在centos7上作用mongodb
    Error: listen EADDRINUSE
    telnet: connect to address xxxxxxx: No route to host
    express-generator安装时出错,最后用VPS解决
    centos7中 npm install express 时Error: Cannot find module 'express'错误
    ubuntu1404服务器版中设置root用户
    python爬虫(1)
  • 原文地址:https://www.cnblogs.com/space007/p/5985640.html
Copyright © 2020-2023  润新知