引入

 Web端即时通讯技术:即时通讯技术简单的说就是实现这样一种功能:服务器端可以即时地将数据的更新或变化反应到客户端,例如消息即时推送等功能都是通过这种技术实现的。但是在Web中,由于浏览器的限制,实现即时通讯需要借助一些方法。这种限制出现的主要原因是,一般的Web通信都是浏览器先发送请求到服务器,服务器再进行响应完成数据的现实更新。

  实现Web端即时通讯的方法:实现即时通讯主要有四种方式,它们分别是轮询、长轮询(comet)、长连接(SSE)、WebSocket。它们大体可以分为两类,一种是在HTTP基础上实现的,包括短轮询、comet和SSE;另一种不是在HTTP基础上实现是,即WebSocket。下面分别介绍一下这四种轮询方式,以及它们各自的优缺点。

当我们要实现一个实时投票系统,或者是实时通讯系统,我们的页面数据总需要更新

我们不能让用户一直去刷新页面。所以就有了轮询,长轮询,以及websock的出现

轮询

既然我想要实时获取后端的数据,那我就每隔2秒给后端发一次请求

这种我们就叫轮询~那它会有一些缺点就是存在延时~就算每秒发一次~也会存在一定的延迟

下面我们看下轮询的代码:

from flask import Flask, render_template, request, jsonify

app = Flask(__name__)

USERS = {
1: {"name": "悟空", "count": 0},
2: {"name": "悟能", "count": 0},
3: {"name": "悟净", "count": 0}, } @app.route("/")
def index():
return render_template("index.html", users=USERS) @app.route("/vote", methods=["POST"])
def vote():
uid = request.json.get("uid")
USERS[uid]["count"] += 1
return "投票成功" @app.route("/get_vote")
def get_vote():
return jsonify(USERS) if __name__ == '__main__':
app.run()

app.py

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script> </head>
<body>
<h1>选丑大赛</h1> <ul>
{% for key, value in users.items()%}
<li id="{{key}}" onclick="vote({{key}})">{{value.name}} ({{value.count}})</li>
{% endfor %}
</ul> <script>
function vote(uid) {
axios.request({
url: "/vote",
method: "POST",
data: {
"uid": uid
}
}).then(function (res) {
console.log(res.data)
})
} function get_vote() {
axios.request({
url: "/get_vote",
method: "GET"
}).then(function (res) {
console.log(res)
for(let key in res.data){
let liEle = document.getElementById(key);
let username = res.data[key]["name"]
let count = res.data[key]["count"]
liEle.innerText = `${username} (${count})`
}
})
} window.onload = function () {
setInterval(get_vote, 2000)
} </script> </body>
</html>

index.html

长轮询

轮询缺点就是延迟,那么如果前端发送过来请求,如果没有数据的更新

后端的请求就阻塞了,直到有数据返回或者超时再返回,这样延迟就可以得到很好的解决

python中有个queue对象,当我们从这个队列里拿不到值的时候,可以阻塞住请求的

import queue
from flask import Flask app = Flask(__name__)
q = queue.Queue() @app.route("/get")
def index():
try:
val = q.get(timeout=20)
except queue.Empty:
val = "超时"
return val @app.route("/vote")
def vote():
q.put("")
return "投票成功" if __name__ == '__main__':
app.run()

queueDemo.py

如果我为每个请求都建立一个q对象,然后阻塞住他们的请求,有数据更新的时候,给他们的q对象返回值就可以了。

from flask import Flask, render_template, request, jsonify, session
import queue
import uuid app = Flask(__name__)
app.secret_key = "lajdgia" USERS = {
1: {"name": "悟空", "count": 0},
2: {"name": "悟能", "count": 0},
3: {"name": "悟净", "count": 0}, }
# 为每个用户建立一个q对象
# 以用户的uuid为key 值为q对象
Q_DICT = {} @app.route("/")
def index():
user_uuid = str(uuid.uuid4())
session["user_uuid"] = user_uuid
Q_DICT[user_uuid] = queue.Queue()
return render_template("index2.html", users=USERS) @app.route("/vote", methods=["POST"])
def vote():
# 投票 循环q对象的dict 给每个q对象返回值
uid = request.json.get("uid")
USERS[uid]["count"] += 1
for q in Q_DICT.values():
q.put(USERS)
return "投票成功" @app.route("/get_vote", methods=["POST", "GET"])
def get_vote():
# 获取投票结果 去自己的q对象里取值 没有夯住 知道有或者超时返回
user_uuid = session.get("user_uuid")
q = Q_DICT[user_uuid]
try:
users = q.get(timeout=30)
except queue.Empty:
users = ""
return jsonify(users) if __name__ == '__main__':
app.run()

app2.py

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script> </head>
<body>
<h1>选丑大赛</h1> <ul>
{% for key, value in users.items()%}
<li id="{{key}}" onclick="vote({{key}})">{{value.name}} ({{value.count}})</li>
{% endfor %}
</ul> <script>
function vote(uid) {
axios.request({
url: "/vote",
method: "POST",
data: {
"uid": uid
}
}).then(function (res) {
console.log(res.data)
})
} function get_votes() {
axios.request({
url: "/get_vote",
method: "POST"
}).then(function (res) {
console.log(res);
if(res.data != ""){
for(let key in res.data){
let liEle = document.getElementById(key);
let username = res.data[key]["name"]
let count = res.data[key]["count"]
liEle.innerText = `${username} (${count})`
}
}
get_votes()
})
} window.onload = function () {
get_votes()
} </script> </body>
</html>

index2.html

websocket

websocket是一个协议,协议规定

连接的时候需要握手,发送的数据需要加密~~连接之后不断开

Flask不带websocket,我们需要下载

下载:pip install gevent-websocket

from flask import Flask, request, render_template
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
import json app = Flask(__name__) USERS = {
1: {"name": "悟空", "count": 0},
2: {"name": "悟能", "count": 0},
3: {"name": "悟净", "count": 0}, } @app.route("/")
def index():
return render_template("index3.html", users=USERS) WEBSOCKET_LIST = []
@app.route("/vote")
def vote():
ws = request.environ.get("wsgi.websocket")
if not ws:
return "HTTP请求"
WEBSOCKET_LIST.append(ws)
while True:
uid = ws.receive()
if not uid:
WEBSOCKET_LIST.remove(ws)
ws.close()
break
uid = int(uid)
USERS[uid]["count"] += 1
name = USERS[uid]["name"]
new_count = USERS[uid]["count"]
for client in WEBSOCKET_LIST:
client.send(json.dumps({"uid": uid, "name": name, "count": new_count})) if __name__ == '__main__':
http_server = WSGIServer(('127.0.0.1', 5000), app, handler_class=WebSocketHandler)
http_server.serve_forever()

app3.py

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script> </head>
<body>
<h1>选丑大赛</h1> <ul>
{% for (key, value) in users.items() %}
<li onclick="vote({{key}})" id="{{key}}">{{value.name}} ({{value.count}})</li>
{% endfor%} </ul> <script>
let ws = new WebSocket('ws://127.0.0.1:5000/vote') function vote(uid) {
ws.send(uid)
}
ws.onmessage = function (event) {
let data = JSON.parse(event.data);
let liEle = document.getElementById(data.uid);
liEle.innerText = `${data.name} (${data.count})`
} </script> </body>
</html>

index3.html

轮询、长轮询、websock的更多相关文章

  1. 使用轮询&长轮询实现网页聊天室

    前言 如果有一个需求,让你构建一个网络的聊天室,你会怎么解决? 首先,对于HTTP请求来说,Server端总是处于被动的一方,即只能由Browser发送请求,Server才能够被动回应. 也就是说,如 ...

  2. Apollo 3 定时/长轮询拉取配置的设计

    前言 如上图所示,Apollo portal 更新配置后,进行轮询的客户端获取更新通知,然后再调用接口获取最新配置.不仅仅只有轮询,还有定时更新(默认 5 分钟一次).目的就是让客户端能够稳定的获取到 ...

  3. 了解轮询、长轮询、长连接、websocket

    业务开发中我们往往会有一些需要即时通信的场景,比如微信扫码登录.聊天功能. 下面这四种方式都可以实现即时通信. 轮询: 浏览器通过定时器每隔一段时间向服务器端发送请求,服务器端收到请求并响应请求.没有 ...

  4. Tornado长轮询和WebSocket

    Http协议是一种请求响应式协议, 不允许服务端主动向客户端发送信息. 短轮询是一种简单的实现服务端推送消息的解决方案, 客户端以一定间隔自动向服务端发送刷新请求, 服务端返回要推送的消息作为响应. ...

  5. 轮询、长轮询、长连接、websocket

    Web端即时通讯技术:即时通讯技术简单的说就是实现这样一种功能:服务器端可以即时地将数据的更新或变化反应到客户端,例如消息即时推送等功能都是通过这种技术实现的.但是在Web中,由于浏览器的限制,实现即 ...

  6. es6- Generator函数实现长轮询

    1.Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同. 语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态.形式上,Gene ...

  7. 长连接、短连接、长轮询和WebSocket

    //转发,格式待整理 2017-08-0519784View0 对这四个概念不太清楚,今天专门搜索了解一下,总结一下: 长连接:在HTTP 1.1,客户端发出请求,服务端接收请求,双方建立连接,在服务 ...

  8. http轮询,长轮询

    轮询,长轮询 轮询 轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接. 优点:后端程序编写比较容易. 缺点:请求中有大半是无用,浪费带宽和服务器资源. 实例:适于小 ...

  9. http长轮询&短轮询

    http 协议介绍: http 协议是请求/响应范式的, 每一个 http 响应都是由一个对应的 http 请求产生的; http 协议是无状态的, 多个 http 请求之间是没有关系的. http ...

随机推荐

  1. C# WPF仿360安全卫士11

    首先上效果图: 这是我的第一篇随笔,最近因为写一个播放器,开始学习WPF相关技术,随着不断入坑,播放器倒是做出来了,掉坑里了... 本着闲着也是闲着的精神,拿360开刀了: 主界面主要使用DMSkin ...

  2. oracle 11g空表不能exp导出问题解决方案

    oracle 11g空表不能exp导出问题解决方案 最近由于要进行迁移服务器代码和数据库,突然发现导出的表少了,通过排查发现空表尽然没有exp导出,真是郁闷啊,虽然是空表没数据,但也不能没有啊,如何是 ...

  3. 第十二次oo作业

    作业十二 规格化设计简介 规格化设计的发展历史 1950年代,第一次分离,主程序与子程序的分离结构是树状模型,子程序可先于主程序编写.通过使用库函数来简化编程,实现最初的代码重用.产生基本的软件开发过 ...

  4. itoa()函数和atoi()函数详解

    C语言提供了几个标准库函数,可以将任意类型(整型.长整型.浮点型等)的数字转换为字符串. 以下是用itoa()函数将整数转换为字符串的一个例子:# include <stdio.h># i ...

  5. Python_每日习题_0004_一年中的第几天

    # 题目 输入某年某月某日,判断这一天是这一年的第几天? # 程序分析 特殊情况,闰年时需考虑二月多加一天: def isLeapYear(y): return (y%400==0 or (y%4== ...

  6. Java开学测试源代码

    package sample; import java.io.IOException;import java.io.Serializable;import java.util.Scanner;impo ...

  7. Notepad++远程连接Linux系统

    首先在官网下载 https://notepad-plus-plus.org/news/notepad-7.6.4-released.html 在命令行数输入ifconfig 查看自己的Linux的ip ...

  8. MySQL 5.7默认ONLY_FULL_GROUP_BY语义介绍

    mysql 5.7版本 出现 ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corre ...

  9. C\C++学习笔记 1

    C++记录1 C的头文件为math.h C++的为 cmath using编译指令 namespace 区分不同产品的函数.Mics::cout Linux::cout cout << 即 ...

  10. java中去除字符串(String)中的换行字符(\r \n \t)

    例1: public class Test { public static void main(String[] args) { String s = "'sds gdasda" ...