python之轮询长轮询websocket

Posted shuyang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python之轮询长轮询websocket相关的知识,希望对你有一定的参考价值。

轮询

ajax轮询 ,ajax轮询 的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。

1、后端代码

from flask import Flask,render_template

app = Flask(__name__)

UUUU = {
    1:{name:,count:1},
    2:{name:,count:1},
    3:{name:,count:1},
}


@app.route(/index)
def index():
    return render_template(index.html,user_list = UUUU)

if __name__ == __main__:
    app.run()

2、前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>最帅的</title>
</head>
<body>
    <ul>
        {% for k,v in user_list.items() %}
            <li>{{k}}: {{v.name}} {{v.count}} </li>
        {% endfor %}
    </ul>
    <script>
        # 重点2秒重新请求
        function reload() {
            window.location.reload()
        }
        setInterval(reload,2000)

    </script>
</body>
</html>    

长轮询

long poll 其实原理跟 ajax轮询 差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消        息才返回或超时,返回完之后,客户端再次建立连接,周而复始,基于事件的触发,一个事件接一个事件。 

Ajax轮询与long poll都属于不断发送http请求,然后等待服务器处理,可以看到http协议一个特点,被动性,服务端不能主动联系客户端,只有客户端发起。

缺点:Ajax轮询需要服务器有很快的处理速度与快速响应。long poll需要很高的并发,体现在同时容纳请求的能力。

1、后端代码

from flask import Flask,render_template,request,session,redirect,jsonify
from uuid import uuid4
from queue import Queue,Empty
import json
app = Flask(__name__)
app.secret_key = "asdfasdfasdf"
UUUU = {
    1:{name:,count:1},
    2:{name:,count:1},
    3:{name:,count:1},
}

# 为每个登录用户保存
# dfasdfadsfasdfadf: Queue()
USER_QUEUE_DICT = {

}

@app.before_request
def check_login():
    if request.path == /login:
        return None
    user_info = session.get(user_info)
    if not user_info:
        return redirect(/login)

@app.route(/login,methods=[GET,POST])
def login():
    if request.method == "GET":
        return render_template(login.html)
    else:
        user = request.form.get(user)
        nid = str(uuid4())
        USER_QUEUE_DICT[nid] = Queue()
        session[user_info] = {nid:nid, user:user }
        return redirect(/index)


@app.route(/index)
def index():
    return render_template(index.html,user_list = UUUU)

@app.route(/query)
def query():
    """每个用户查询最新投票信息"""
    ret = {status:True,data:None}
    current_user_nid = session[user_info][nid]
    queue = USER_QUEUE_DICT[current_user_nid]
    try:
        # {‘uid‘:1, ‘count‘:6}
        ret[data] = queue.get(timeout=10) #十秒后断开,再连
    except Empty as e:
        ret[status] = False
    # return jsonify(ret)
    return json.dumps(ret)


@app.route(/vote)
def vote():
    """
    用户投票
    :return:
    """
    uid = request.args.get(uid)
    old = UUUU[uid][count]
    new = old + 1
    UUUU[uid][count] = new

    for q in USER_QUEUE_DICT.values():
        q.put({uid:uid, count:new})

    return "投票成功"


if __name__ == __main__:
    app.run(host=0.0.0.0,threaded=True)

2、前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>最帅</title>
</head>
<body>
    <ul>
        {% for k,v in user_list.items() %}
            <li style="cursor: pointer;" ondblclick="doVote(‘{{k}}‘)" id="user_{{k}}">{{k}}: {{v.name}} <span>{{v.count}}</span> </li>
        {% endfor %}
    </ul>
    <!--<script src="/static/jquery-1.12.4.js"></script>-->
    <script src="{{ url_for(‘static‘,filename=‘jquery-1.12.4.js‘) }}"></script>
    <script>
        
        $(function () {
            get_data();
        })
        
        /*
        查询最新信息
         */
        function get_data() {
            $.ajax({
                url: /query,
                type:GET,
                dataType:json,
                success:function (arg) {
                    if(arg.status){
                        var liId = "#user_" + arg.data.uid;
                        $(liId).find(span).text(arg.data.count);
                    }
                    get_data();
                }
                
            })
        }

        /*
        投票
         */
        function doVote(uid) {
            $.ajax({
                url:/vote, //     /vote?uid=1
                type:GET,
                data:{
                    uid:uid
                },
                success:function (arg) {

                }
            })
        }
    </script>
</body>
</html>

 

websocket

webSocket是html5一种新的协议,实现了浏览器与服务器之间的全双工通信,能很好的节省服务器资源与带宽,并在服务器端与浏览器端实现实时通行,他建立在TCP之上, 同http一样,通过tcp来传输数据。

   只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,服务器端会知道连接的信息,知道客户端关闭请求,同时由服务器主动推送,当有信息需要发送时,直接发送。客户端的连接通过session对象存储,能够实现实时推送。

1、安装

pip3 install gevent-websocket

2、后端代码

from flask import Flask,render_template,request,session,redirect,jsonify
import uuid
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
import json


app = Flask(__name__)
app.secret_key = xfsdfqw

USERS = {
    1:{name:,count:0},
    2:{name:,count:0},
    3:{name:,count:0},
}


@app.before_request
def before_request():
    if request.path == /login:
        return None
    user_info = session.get(user_info)
    if user_info:
        return None
    return redirect(/login)


@app.route(/login,methods=[GET,POST])
def login():
    if request.method == "GET":
        return render_template(login.html)
    else:
        uid = str(uuid.uuid4())
        session[user_info] = {id:uid,name:request.form.get(user)}
        return redirect(/index)


@app.route(/index)
def index():
    return render_template(index.html,users=USERS)

# 为每个登录用户保存socket字典
WS_DICT = {

}

@app.route(/message)
def message():
    if request.environ.get(wsgi.websocket):
        ws = request.environ[wsgi.websocket]
        # 1. 刚连接成功
        uid = session.get(user_info).get(id)
        WS_DICT[uid] = ws

        from geventwebsocket.websocket import WebSocket
        while True:
            # 2. 等待用户发送消息,并接受
            message = ws.receive()
            # 关闭:message=None
            if not message:
                del WS_DICT[uid]
                break

            old = USERS[message][count]
            new = old + 1
            USERS[message][count] = new

            data = {user:message,count:new}

            for k,v in WS_DICT.items():
                # 3. 向客户端推送消息
                v.send(json.dumps(data))

    return "Connected!"

if __name__ == __main__:
    http_server = WSGIServer((127.0.0.1, 5000), app, handler_class=WebSocketHandler)
    http_server.serve_forever()

3、前端代码

#login
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="post">
    <input type="text" name="user">
    <input type="submit" value="提交">
</form>
</body>
</html>
# index
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>投票系统</h1>
    <a onclick="closeConn();">关闭连接</a>
    <a onclick="createConn();">创建连接</a>
    <ul>
        {% for k,v in users.items() %}
            <li id="user_{{k}}"  ondblclick="vote(‘{{k}}‘)">{{v.name}} <span>{{v.count}}</span> </li>
        {% endfor %}

    </ul>

    <script src="{{ url_for(‘static‘,filename=‘jquery-3.3.1.min.js‘)}}"></script>
    <script>

        var socket = null;

        function socketInit() {
            socket.onopen = function () {
            /* 与服务器端连接成功后,自动执行 */
        };

            socket.onmessage = function (event) {
                /* 服务器端向客户端发送数据时,自动执行 */
                var response = JSON.parse(event.data); // {user:1,count:new}
                var nid = #user_ + response.user;
                $(nid).find(span).text(response.count)
            };

            socket.onclose = function (event) {
                /* 服务器端主动断开连接时,自动执行 */
            };

        }

        /*
        我要投票
        id:帅哥id
         */
        function vote(id) {

            socket.send(id);
        }

        function closeConn() {
            socket.close()
        }
        function createConn() {
            socket = new WebSocket("ws://127.0.0.1:5000/message");
            socketInit();
        }
    </script>
</body>
</html>

 

以上是关于python之轮询长轮询websocket的主要内容,如果未能解决你的问题,请参考以下文章

轮询长轮询和websocket

轮询长轮询长连接socket连接WebSocket

轮询长轮询长连接socket连接WebSocket

轮询长轮询comet长连接SSEwebsocket

轮询长轮询comet长连接SSEwebsocket

网页端IM即时通讯技术入门之短轮询长轮询SSEWebSocket