Web即时通信

所谓Web即时通信,就是说我们可以通过一种机制在网页上立即通知用户一件事情的发生,是不需要用户刷新网页的。Web即时通信的用途有很多,比如实时聊天,即时推送等。如当我们在登陆浏览知乎时如果有人回答了我们的问题,知乎就会即时提醒我们,再比如现在电子商务的在线客服功能。这些能大大提高用户体验的功能都是基于Web即时通信实现的。

  • 普通HTTP流程
    1. 客户端从服务器端请求网页
    2. 服务器作出相应的反应
    3. 服务器返回相应到客户端

而由于HTTP请求是无状态的,也就是说每次请求完成后,HTTP链接就断开了,服务器和浏览器互相之间是完全不可知的,只有下一次再发起一次请求 才能更新相应的信息。谈到这里我们就不难想到,我们可以简单的让浏览器每隔一个周期就发起一次请求,这样就能在一定程度上模拟实时效果了,这也就是轮训,术语叫做Polling。

  • Polling流程
    1. 客户端使用普通的http方式向服务器端请求网页
    2. 客户端执行网页中的JavaScript轮询脚本,定期循环的向服务器发送请求(例如每5秒发送一次请求),获取信息
    3. 服务器对每次请求作出响应,并返回相应信息,就像正常的http请求一样

通过轮训的方式我们就可以相对即时的获取信息。但是由于轮训的原理是使浏览器频繁的向服务器发起请求,这在一定程度上会造成性能效率问题。为了优化 这些性能问题,人们又想到了一种方法。那就是在服务器接收到请求的时候不理解返回,而是只有当有数据变化(或者超时)的时候才返回。这样一来,我们就可以 利用一次请求最大可能的保持连接的有效性,大大的减少了Polling中的请求次数。这个方法叫做长轮训,也叫做Long-Polling。

以上方法是实现Web实时通信的常用方法。当然在HTML5出来之后,我们就有更好的选择啦。在HTML5中,我们可以使用SSE或者是WebSocket。SSE的全称是Server Send Event,听名字就很好理解啦。也就是由服务器来推送数据。看到这里是不是兴奋呢?其实很多情况下,我们只需要这种简单的功能:由服务器推送数据到浏览器。比如推送比赛信息、股价的变化等等。

如果SSE还不能满足我们的需求的话,我们完全就可以使用WebSocket啦。当使用WebSocket时,浏览器和服务器之间就建立了一个全双工通道,互相都可以发送消息,完全的做到了及时,就像使用tcp socket一样。

  • SSE和WebSocket的简单对比:
    • WebSocket是全双工通道,可以双向通信,功能更强;SSE是单向通道,只能服务器向浏览器端发送。
    • WebSocket是一个新的协议,需要服务器端支持;SSE则是部署在HTTP协议之上的,现有服务器软件都支持。
    • SSE是一个轻量级协议,相对简单;WebSocket是一种较重的协议,相对复杂。

到这里我们就基本了解了一些事先Web实时通信的机制,下一节中,我们将使用SSE实现一个简单的在线聊天室。

基于SSE的在线聊天室的实现

在线聊天室推送消息有很多种方式,在这门课程中我们使用SSE来实现。为了方便接收消息,我们借助Redispub/sub功能来接收和发送消息。Web服务器端我们将使用Flask实现。如果对Flask不是很熟悉,也可以在实验楼学习相关的Flask课程。(http://www.shiyanlou.com/)

1. SSE 的工作方式

在上面的课程中,我们了解到SSE是基于HTTP实现的,那么浏览器怎么样知道这是一个服务器事件流呢?其实很简单啦,就是将HTTP的头部Content-Type设置成text/event-stream就可以了。其实SSE,就是浏览器向服务器发送一个HTTP请求,然后服务器不断单向地向浏览器推送"信息",这些信息的格式也非常简单,就是前缀data:加上发送的数据内容,然后以\n\n结尾。

2. Redis中的订阅功能

Redis是很流行的一个内存数据库,可以用于实现缓存,队列等服务。在这门项目课程中我们将使用的Redis的发布/订阅功 能。简单来说,我们所谓订阅功能就是我们可以订阅一些频道,然后当这些频道有新的消息的时候我们就可以自动接收这些信息。当服务器接收到浏览器POST过 来的消息的时候,会将这些信息发布到特定的频道中。接着我们之前订阅了这些频道的客户端就回自动收到这些消息,最后我们就将这些消息通过SSE推送到客户端。

3. 实现

经过上面的分析,整个聊天室的流程已经很清晰啦。下面通过源代码注释的方式进行分析吧。在/home/shiyanlou目录下,创建目录code,然后在该目录下创建源文件app.py

# 消息生成器
def event_stream():
pubsub = r.pubsub()
# 订阅'chat'频道
pubsub.subscribe('chat')
# 开始监听消息,如果有消息产生在返回消息
for message in pubsub.listen():
print message
# Server-Send Event的数据格式以'data:'开始
yield 'data: %s\n\n' % message['data'] # 登陆函数,首次访问需要登陆
@app.route('/login', methods=['GET', 'POST'])
def login():
if flask.request.method == 'POST':
# 将用户信息记录到session中
flask.session['user'] = flask.request.form['user']
return flask.redirect('/')
return '<form action="" method="post">user: <input name="user">' # 接收javascript post过来的消息
@app.route('/post', methods=['POST'])
def post():
message = flask.request.form['message']
user = flask.session.get('user', 'anonymous')
now = datetime.datetime.now().replace(microsecond=0).time()
# 将消息发布到'chat'频道中
r.publish('chat', u'[%s] %s: %s' % (now.isoformat(), user, message))
return flask.Response(status=204)

详细代码请登录实验楼http://www.shiyanlou.com/courses/?course_type=project&tag=all

4. 运行

由于使用了Redis,所以需要安装redis服务器,通过以下步骤就可以将redis服务器,以及相关的依赖包安装好。

$ sudo apt-get update
$ sudo apt-get install redis-server
$ sudo service redis start
$ sudo pip install redis
$ sudo pip install flask

安装完成以后,运行,然后通过浏览器访问http://127.0.0.1:8989就看到效果啦.

另有其他项目课的详细讲解和内容欢迎登陆实验楼http://www.shiyanlou.com/courses/?course_type=project&tag=all

官方网站:实验楼 http://www.shiyanlou.com

基于Server-Sent Event的简单在线聊天室的更多相关文章

  1. 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。

    基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...

  2. 基于JQuery+JSP的无数据库无刷新多人在线聊天室

    JQuery是一款非常强大的javascript插件,本文就针对Ajax前台和JSP后台来实现一个无刷新的多人在线聊天室,该实现的数据全部存储在服务端内存里,没有用到数据库,本文会提供所有源程序,需要 ...

  3. Android简单的聊天室开发(client与server沟通)

    请尊重他人的劳动成果.转载请注明出处:Android开发之简单的聊天室(client与server进行通信) 1. 预备知识:Tcp/IP协议与Socket TCP/IP 是Transmission ...

  4. 基于Java的在线聊天室

    概述 Java socket编程,实现一个在线聊天室, 实现在线用户群聊,私聊,发送文件等功能. 详细 代码下载:http://www.demodashi.com/demo/13623.html 一. ...

  5. .NET Core 基于Websocket的在线聊天室

    什么是Websocket 我们在传统的客户端程序要实现实时双工通讯第一想到的技术就是socket通讯,但是在web体系是用不了socket通讯技术的,因为http被设计成无状态,每次跟服务器通讯完成后 ...

  6. java Socket实现简单在线聊天(二)

    接<java Socket实现简单在线聊天(一)>,在单客户端连接的基础上,这里第二步需要实现多客户端的连接,也就需要使用到线程.每当有一个新的客户端连接上来,服务端便需要新启动一个线程进 ...

  7. vue实现简单在线聊天

    vue实现简单在线聊天 引用mui的ui库,ES6的 fetch做网络请求 //html <!DOCTYPE html> <html> <head> <met ...

  8. 使用WebSocket实现简单的在线聊天室

    前言:我自已在网上找好了好多 WebSocket 制作 在线聊天室的案列,发现大佬们写得太高深了 我这种新手看不懂,所以就自已尝试写了一个在线简易聊天室 (我只用了js 可以用jq ) 话不多说,直接 ...

  9. Asp.NET MVC 使用 SignalR 实现推送功能二(Hubs 在线聊天室 获取保存用户信息)

    简单介绍 关于SignalR的简单实用 请参考 Asp.NET MVC 使用 SignalR 实现推送功能一(Hubs 在线聊天室) 在上一篇中,我们只是介绍了简单的消息推送,今天我们来修改一下,实现 ...

随机推荐

  1. PHP干货技巧文,一些PHP性能的优化

    PHP优化对于PHP的优化主要是对php.ini中的相关主要参数进行合理调整和设置,以下我们就来看看php.ini中的一些对性能影响较大的参数应该如何设置. # vi /etc/php.ini (1) ...

  2. iOS开发小技巧--计算label的Size的方法总结

    计算label的Size方法 sizeWithAttributes:方法 适用于不换行的情况,宽度不受限制的情况 /// 根据指定文本和字体计算尺寸 - (CGSize)sizeWithText:(N ...

  3. 清北学堂模拟day6 兔子

    [问题描述] 在一片草原上有N个兔子窝,每个窝里住着一只兔子,有M条路径连接这些窝.更特殊地是,至多只有一个兔子窝有3条或更多的路径与它相连,其它的兔子窝只有1条或2条路径与其相连.换句话讲,这些兔子 ...

  4. Configuration for Python to run on Android

    It's exiting to learn to make app on Android with python. But when I check <Head First Python> ...

  5. volley(2) 参数code : or_barcode, pr_ismsd:false , method:GET

    1. 来自于WHCombineBatchFragment.java /** * 当编辑框里面的内容完成的时候,自动的,同时获取服务器的批量数 */private void barcodeEnterEv ...

  6. 关于兄弟QWidget间的位置重叠

    转自:http://hi.baidu.com/dbzhang800/item/a7bf1f1e983c6af964eabf45?qq-pf-to=pcqq.group 缘起 csdn上一用户抱怨:她的 ...

  7. HttpContext详解【转】

    HttpContext 类:封装有关个别 HTTP 请求的所有 HTTP 特定的信息. 在处理请求执行链的各个阶段中,会有一个对象在各个对象之间进行传递,也即会保存请求的上下文信息,这个对象就是Htt ...

  8. BZOJ 2521: [Shoi2010]最小生成树(最小割)

    题意 对于某一条无向图中的指定边 \((a, b)\) , 求出至少需要多少次操作.可以保证 \((a, b)\) 边在这个无向图的最小生成树中. 一次操作指: 先选择一条图中的边 \((u, v)\ ...

  9. 家庭记账本之微信小程序(四)

    json的学习 JSON:JavaScript 对象表示法(JavaScript Object Notation). JSON 是存储和交换文本信息的语法.类似 XML. JSON 比 XML 更小. ...

  10. Linux系统级日志系统

    linux日志系统,在不同的发行版本名字不同.本质一样都是对系统运行非正常状态的记录... rhel5.x    syslogrhel6.x    rsyslog service rsyslog st ...