首页 > 代码库 > Gevent的长轮询实现方法详解

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;

            width:400px;

        }

    </style>

<head>

<body>

    <div id="main">

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

    </div>

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

    <script src="http://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 = http://www.mamicode.com/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 = http://www.mamicode.com/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/

Gevent的长轮询实现方法详解