zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    Android 3.0 r1 API中文文档(108) —— ExpandableListAdapter
    Android 3.0 r1 API中文文档(113) ——SlidingDrawer
    Android 3.0 r1 API中文文档(105) —— ViewParent
    Android 中文 API (102)—— CursorAdapter
    Android开发者指南(4) —— Application Fundamentals
    Android开发者指南(1) —— Android Debug Bridge(adb)
    Android中文API(115)——AudioFormat
    Android中文API(116)——TableLayout
    Android开发者指南(3) —— Other Tools
    Android中文API (110) —— CursorTreeAdapter
  • 原文地址:https://www.cnblogs.com/space007/p/5985640.html
Copyright © 2011-2022 走看看