Browser and Server Sync (Polling, Comet, Long Polling, WebSocket)
This article was created at 4265 days ago. It is too long, so please pay more attention.
1 前言#
这只是一篇简单介绍浏览器与服务器之间的实时数据交换的方法。 在客户端使用的是 coffeescript ,接触下来感觉这种语法还是不错的, 然后在学习的过程中,貌似coffeescript借鉴了许多 Ruby 的语法, 所以接下来我准备去看看Ruby,当然这个是题外话啦。 一旦接受了coffeescript这种设定,还是很带感的。
然后服务器用的是 python 的 Flask 这一WEB框架以及 nodejs
主要参考的是:Browser 與 Server 持續同步的作法介紹 (Polling, Comet, Long Polling, WebSocket)
2 环境的搭建#
2.1 Flask#
- Install 安装步骤,请移步 这里 ,这里是官方的安装方式,在这里我接触到了python的虚拟环境。 感觉用这个virtualenv的确不错,然后我找到了一篇介绍这种的文章:virtualenv
- Quick Start 请移步这里 。我也是跟着快速教程一步一步做的,写出来的服务器也很简单。 毕竟这篇文章的主题不是这个。
2.2 Nodejs#
关于如何安装 nodejs 以及如何使用我在此不多累述。官方文档写的很详细。 然后我使用的是 expressjs 这一WEB框架。安装方式和快速入门点击 QuickStart 。
在这里着重写一下使用 coffeescript
来写nodejs的代码。
具体可以看这篇文章:My Node.js Express + CoffeeScript setup
我的做法只是用来其中的一条命令:
$ sudo npm install -g js2coffee
将express生成的app.js转成了app.coffee,然后将 package.json 中的
"start": "node app.js"
变成了:
"start": "coffee app.coffee"
具体的在我上面提到文章中有详细介绍。当然还可以看看这个:Express-coffee
3 Polling#
这是轮询的方式,是一种很常见的解决方案。然后我这里没有写代码。 思路就是使用setInterval()函数,定时访问服务器。构成一个一个polling.
4 Comet#
等待填坑……
5 Long Polling#
长轮询方式。 代码:
Post = | |
getId: -> | |
$.ajax { | |
type: 'POST' | |
url: '/getId' | |
context: $('body') | |
success: (data) -> | |
successHandle(data) | |
return | |
error: (xhr, type) -> | |
console.log xhr, type | |
return | |
} | |
return | |
# Success Handle | |
successHandle = (data) -> | |
console.log data.u_id | |
$('#show').append(data.u_id) | |
Post.getId() | |
return | |
# after loading run the below codes | |
$ -> | |
Post.getId() | |
return |
from flask import Flask, session, redirect, url_for, escape, request, render_template, jsonify | |
import os | |
import random | |
import time | |
# app = Flask(__name__) | |
app = Flask(__name__, | |
# static_path='/static', | |
static_folder='static', | |
template_folder='templates') | |
@app.route('/') | |
def index(): | |
if 'username' in session: | |
return render_template('logged.html', | |
number = random.random(), | |
username = escape(session['username']),) | |
return render_template('index.html') | |
@app.route('/login', methods=['GET', 'POST']) | |
def login(): | |
""" | |
""" | |
if request.method == 'POST': | |
session['username'] = request.form['username'] | |
return redirect(url_for('index')) | |
return render_template('login.html') | |
@app.route('/logout') | |
def logout(): | |
# remove the username from the session if it's there | |
session.pop('username', None) | |
return redirect(url_for('index')) | |
# set the secret key. keep this really secret: | |
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' | |
@app.route('/getId', methods=['GET', 'POST']) | |
def getId(): | |
while True: | |
time.sleep(3) | |
msg = jsonify(u_id = '100') | |
return msg | |
# with app.app_context(): | |
# url_for('static', filename='zepto.min.js') | |
if __name__ == '__main__': | |
app.debug = True | |
app.run() |
6 WebSocket#
等待填坑……
7 Socket.IO#
Socket.IO 这个我个人感觉不错,支持的浏览器也很多,然后使用的是nodejs。 有空的时候看看源代码,看看究竟是如何实现的。
然后下面的代码都是按照官方的步骤做的,只是稍微修改了一下。具体的可以参照 这里
代码:
extends layout | |
block content | |
h1= title | |
p Welcome to #{title} |
doctype 5 | |
html | |
head | |
title= title | |
link(rel='stylesheet', href='/stylesheets/style.css') | |
script(src="/socket.io/socket.io.js") | |
script(src="/javascripts/zepto.min.js") | |
script(src="/javascripts/app.js") | |
body | |
block content |
# $show = document.getElementById('show') | |
show = (data) -> | |
$show = $('body') | |
console.log $show | |
msg = data.hello || data.id | |
$show.append "<p>#{msg}</p>" | |
return | |
socket = io.connect 'http://localhost:3000' | |
socket.on 'news', (data) -> | |
console.log data | |
show data | |
socket.emit 'my other event', {my: 'data'} | |
return | |
socket.on 'random', (data) -> | |
show data | |
return |
### | |
Module dependencies. | |
### | |
express = require("express") | |
socket_io = require("socket.io") | |
routes = require("./routes") | |
user = require("./routes/user") | |
http = require("http") | |
path = require("path") | |
app = express() | |
app.configure -> | |
app.set "port", process.env.PORT or 3000 | |
app.set "views", __dirname + "/views" | |
app.set "view engine", "jade" | |
app.use express.favicon() | |
app.use express.logger("dev") | |
app.use express.bodyParser() | |
app.use express.methodOverride() | |
app.use app.router | |
app.use express.static(path.join(__dirname, "public")) | |
app.configure "development", -> | |
app.use express.errorHandler() | |
app.get "/", routes.index | |
app.get "/users", user.list | |
server = http.createServer(app) | |
server.listen app.get("port"), -> | |
console.log "Express server listening on port " + app.get("port") | |
io = socket_io.listen server | |
io.sockets.on 'connection', (socket) -> | |
socket.emit 'news', {hello: 'world'} | |
setInterval -> | |
socket.emit 'random', { id: Math.random() } | |
return | |
, 1000 | |
socket.on 'my other event', (data) -> | |
console.log(data) | |
return | |
return |
8 后记#
然后接下来需要思考的是数据库更新,如何通知web服务器发送更新数据? 继续等待填坑……