转自:https://blog.shonenada.com/post/websocket-with-flask/

WebSocket with Flask

HTML5 以前,HTML 还不支持 WebSocket ,当时如果要进行实时的内容更新,要么使用 Ajax轮询(Polling)或者使用 Comet 技术。

Non-Websocket

Ajax 轮询

在 2005 年, Jesse James Garrett 提出 Ajax (Asynchronous JavaScript and XML, 异步 Javascript 和 XML)。具体请看Ajax: A New Approach to Web Applications 。并且从那时开始流行使用 Ajax 进行异步处理客户端请求。【关于异步处理请求的历史,可以看 http://en.wikipedia.org/wiki/Ajax_(programming) 中相关的介绍】。 XMLHttpRequest 在后台对服务器发起 request ,当收到 response 的时候,进行 DOM 操作,从而达到部分更新页面内容的目的(而不需要整个页面刷新)。

Ajax 轮询 可以做到接近实时的更新内容,但是因为是由客户端发起请求,即服务器处于被动的状态,这种“实时”存在缺陷: (1) 伪实时。服务器有更新的时候,只有客户端发起请求,服务器才能将更新返回到客户端。 (2) 数据更新量少的时候,容易造成浪费带宽、流量。 (3) 请求频率难以把握。太快会对服务器造成过大的压力,而太慢又不够“实时”,权衡频率需要考虑的因素很多。

Comet 技术

Comet 是指不需要客户端浏览器安装任何插件,仅靠浏览器和服务器之间的长 HTTP 连接实现服务器向客户端通信(服务器推)的技术。 Comet 有两种方式: Ajax长轮询 和 iframe with htmlfile stream

iframe with htmlfile streaming

这种技术,暂时没使用过。基本原理是使用 iframe 标签在 html 中插入一个隐藏的帧,向服务器建立长连接,服务器不断地向 iframe 输入数据。

Ajax 长轮询

Ajax 长轮询本质上也是 Ajax 轮询,不同的是,在服务器端做了些修改。当服务器没有更新的时候,服务器将请求阻塞,直到 有更新 或 连接超时。当请求结束之后再进行第二次的请求。

这种方式基本上可以避开 Ajax 轮询的缺陷。 Tornado 框架中的 Asynchronous 功能就是通过阻塞请求实现异步更新。 通过 Tornado 框架提供的 Asynchronous 功能可以实现实时数据传递。欢迎参考我在学习使用 tornado 异步功能时实现的两段应用:

  1. https://github.com/shonenada/chat-in-command-line
  2. https://github.com/shonenada/guess-number // 这程序功能不完善,但实现了异步的功能。

WebSocket

WebSocket 是 HTML5 的新功能,它是一种 TCP 协议。当客户端和服务器完成握手,建立连接之后,ws 就如普通 socket 一样,在两者之间进行通信。

理解了基本通信原理,就可以进行编程了。

前面已说,WS 是一种 TCP 协议,所以是语言无关的,用任何语言都可以实现服务器端的编程。我选择了 Python,使用 _flask: http://flask.pocoo.org/ 作为框架,以 _Gevent: http://www.gevent.org/ 和 _gevent-websocket:https://pypi.python.org/pypi/gevent-websocket/ 做 HttpServer。

实时更新基本的实现思路:

  1. 客户端发起 ws 连接请求
  2. 服务器响应,并且把 ws 加入到 observer 数组中。
  3. 当某一 ws 向服务器发送信息时,服务器遍历 observers 数组向每一个元素发送信息。
  4. ws 断开连接时,从 observer 中剔除。

具体实现代码:

# manage.py
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from flask import Flask, request, render_template, abort import message msgsrv = message.MessageServer() app = Flask(__name__) @app.route('/')
def index():
return render_template('message.html') @app.route('/message/')
def message():
if request.environ.get('wsgi.websocket'):
ws = request.environ['wsgi.websocket']
msgsrv.observers.append(ws)
while True:
if ws.socket:
message = ws.receive()
if message:
msgsrv.add_message("%s" % message)
else:
abort(404)
return "Connected!" if __name__ == '__main__':
http_server = WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
http_server.serve_forever()
# message.py
from geventwebsocket import WebSocketError class MessageServer(object): def __init__(self):
self.observers = [] def add_message(self, msg):
for ws in self.observers:
try:
ws.send(msg)
except WebSocketError:
self.observers.pop(self.observers.index(ws))
print ws, 'is closed'
continue
<!-- templates/message.html -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="zh-CN"/>
<title>实时消息</title>
<link rel="stylesheet" href="http://getbootstrap.com/2.3.2/assets/css/bootstrap.css">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function(){
$('form').submit(function(event){
ws.send($(this).serialize());
return false;
});
if ("WebSocket" in window) {
ws = new WebSocket("ws://" + document.domain + ":5000/message/");
ws.onmessage = function (msg) {
console.log(msg.data);
};
} else {
alert("WebSocket not supported");
}
window.onbeforeunload = function() {
ws.onclose = function () {
console.log('unlodad')
};
ws.close()
};
});
</script>
</head>
<body>
<div class="header container">
<h1>实时消息</h1>
<ul class="tabs">
<li class="active">
<a href="/">DEMO</a>
</li>
</ul>
</div>
<div class="container">
Pls check your Chrome console.
<form class="row" id="message_form">
<div class="span10">
<div class="clearfix">
<label for="chat_content">消息</label>
<div class="input">
<textarea id="chat_content" name="content" class="xlarge" rows="6"></textarea>
</div>
</div>
<div class="well align-center">
<input type="submit" class="btn primary" value="发布">
&nbsp;
<input type="reset" class="btn" value="清空">
</div>
</div>
</form>
</div>
<div class="footer container">
<p>
&copy; Copyright by shonenada
</p>
</div>
</body>
</html>

~接下来可以实现 HTML5 的桌面直播了。

WebSocket with Flask的更多相关文章

  1. python 全栈开发,Day139(websocket原理,flask之请求上下文)

    昨日内容回顾 flask和django对比 flask和django本质是一样的,都是web框架. 但是django自带了一些组件,flask虽然自带的组件比较少,但是它有很多的第三方插件. 那么在什 ...

  2. flask总结之session,websocket,上下文管理

    1.关于session flask是带有session的,它加密后存储在用户浏览器的cookie中,可以通过app.seesion_interface源码查看 from flask import Fl ...

  3. WebSocket 实现链接 群聊(low low low 版本)

    py 文件: """ 下载 gevent-websocket 0.10.1 基于Flask + geventWebSocket 建立连接,发送消息,实现群消息功能. &q ...

  4. WebSocket 实现链接 发送消息

    Websocket 原理浅析地址: https://www.cnblogs.com/yuanyongqiang/articles/10457793.html 直接上代码: myWebSocket.py ...

  5. websocket 群聊,单聊,加密,解密

    群聊 from flask import Flask, request, render_templatefrom geventwebsocket.handler import WebSocketHan ...

  6. Websocket实现群聊、单聊

    Websocket 使用的第三方模块:gevent-websocket 群聊 ws群聊.py中的内容 from flask import Flask, request, render_template ...

  7. flask+socketio+echarts3 服务器监控程序(基于后端数据推送)

    本文地址:http://www.cnblogs.com/hhh5460/p/7397006.html 说明 以前的那个例子的思路是后端监控数据存入数据库:前端ajax定时查询数据库. 这几天在看web ...

  8. websocket实现群聊

    server # @File: 群聊 from flask import Flask, render_template, request from geventwebsocket.handler im ...

  9. WebSocket 笔记

    WebSocket介绍 WebSocket+Flask开启一个WebSocket服务 群聊小Demo 私聊小Demo WebSocket介绍 - 菜鸟教程详解连接 - 下载:pip install g ...

随机推荐

  1. Linux suse x86_64 环境上部署Hadoop启动失败原因分析

    一.问题症状: 在安装hadoop的时候报类似如下的错误: # A fatal error has beendetected by the Java Runtime Environment: # #  ...

  2. Python应用与实践【转】

    转自:http://www.cnblogs.com/skynet/archive/2013/05/06/3063245.html 目录 1.      Python是什么? 1.1.      Pyt ...

  3. 图片处理工具类 - ImageUtils.java

    纯JAVA实现的图片处理工具类,提供图片的裁剪.压缩.获取尺寸.制作圆角等方法. 源码如下:(点击下载 -ImageUtils.java .FolderUtils.java .commons-io-2 ...

  4. eclipse启动报错 java was started but returned exit code = -805306369

    前几天还工作的好好的eclipse昨天下午启动时突然报错 报错如图: 妹的,好端端突然报错,非常奇怪,关键还是返回一堆看不懂的东西,细看都是eclipse.ini里面的配置信息,看到熟悉的jdk,误以 ...

  5. Volley HTTP库系列教程(5)自定义一个Volley请求

    Implementing a Custom Request Previous  Next This lesson teaches you to Write a Custom Request parse ...

  6. Newtonsoft.Json序列化和反序列之javascriptConvert.SerializeObject,DeserializeObject,JsonWriter,JsonReader

    这里下载:http://www.newtonsoft.com/products/json/安装:   1.解压下载文件,得到Newtonsoft.Json.dll   2.在项目中添加引用.. jav ...

  7. 第三篇 从EXCEL电子表格到数据库

    一个靠EXCEL电子表格处理各部门业务数据的公司和一个使用一个统一的数据库存储各个部门用到的业务数据并提供大量权限不同的使用界面给用户的公司两者有什么不同呢?   EXCEL电子表格是数据和操纵数据的 ...

  8. git和其他版本控制系统的区别

    所有除了Git以外的版本控制系统都使用增量存储方式来保存不同版本,而Git则在每一个commit时,保存一个整个文件的content copy,除非那个文件没有做过改动.Git和其他版本系统的主要区别 ...

  9. EntityFramework:支持同一事务提交的批量删除数据实现思路

    一切从一段代码说起... 下面一段代码是最近我在对一EF项目进行重构时发现的. protected override void DoRemove(T entity) { this.dbContext. ...

  10. C# 对List成员排序的简单方法

    网上看到的方法,实在太方便了,转过来保存,原链接: http://blog.csdn.net/wanzhuan2010/article/details/6205884 using System; us ...