websocket之django轻巧使用

Web
应用的信息交互过程通常是客户端通过浏览器发出一个请求,服务器端接收和审核完请求后进行处理并返回结果给客户端,然后客户端浏览器将信息呈现出来,这种机制对于信息变化不是特别频繁的应用尚能相安无事,但是对于那些实时要求比较高的应用来说,比如说在线游戏、在线证券、设备监控、新闻在线播报、RSS
订阅推送等等,当客户端浏览器准备呈现这些信息的时候,这些信息在服务器端可能已经过时了。所以保持客户端和服务器端的信息同步是实时
Web 应用的关键要素,对 Web 开发人员来说也是一个难题。在 WebSocket
规范出来之前,开发人员想实现这些实时的 Web
应用,不得不采用一些折衷的方案,其中最常用的就是轮询 (Polling) 和 Comet
技术,而 Comet
技术实际上是轮询技术的改进,又可细分为两种实现方式,一种是长轮询机制,一种称为流技术。下面我们简单介绍一下这几种技术:

WebSocket protocol:

轮询:

WebSocket protocol
是HTML5一种新的协议。它是实现了浏览器与服务器全双工通信(full-duplex).HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并达到实时通讯.
我们知道,传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如
浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据;这种客户端是主动方,服务端是被动方的传统Web模式
对于信息变化不频繁的Web应用来说造成的麻烦较小,而对于涉及实时信息的Web应用却带来了很大的不便,如带有即时通信、实时数据、订阅推送等功能的应
用。在WebSocket规范提出之前,开发人员若要实现这些实时性较强的功能,经常会使用折衷的解决方法:轮询(polling)和Comet技术。其实后者本质上也是一种轮询,只不过有所改进。
 
轮询是最原始的实现实时Web应用的解决方案。轮询技术要求客户端以设定的时间间隔周期性地向服务端发送请求,频繁地查询是否有新的数据改动。明显地,这种方法会导致过多不必要的请求,浪费流量和服务器资源。
 
Comet技术又可以分为长轮询和流技术。长轮询改进了上述的轮询技术,减小了无用的请求。它会为某些数据设定过期时间,当数据过期后才会向服务端发送请求;这种机制适合数据的改动不是特别频繁的情况。流技术通常是指客户端使用一个隐藏的窗口与服务端建立一个HTTP长连接,服务端会不断更新连接状态以保持HTTP长连接存活;这样的话,服务端就可以通过这条长连接主动将数据发送给客户端;流技术在大并发环境下,可能会考验到服务端的性能。
 
这两种技术都是基于请求-应答模式,都不算是真正意义上的实时技术;它们的每一次请求、应答,都浪费了一定流量在相同的头部信息上,并且开发复杂度也较大。
 
伴随着HTML5推出的WebSocket,真正实现了Web的实时通信,使B/S模式具备了C/S模式的实时通信能力。WebSocket的工作流程是这
样的:浏览器通过JavaScript向服务端发出建立WebSocket连接的请求,在WebSocket连接建立成功后,客户端和服务端就可以通过
TCP连接传输数据。因为WebSocket连接本质上是TCP连接,不需要每次传输都带上重复的头部数据,所以它的数据传输量比轮询和Comet技术小了很多.

这是最早的一种实现实时 Web
应用的方案。客户端以一定的时间间隔向服务端发出请求,以频繁请求的方式来保持客户端和服务器端的同步。这种同步方案的最大问题是,在一些数据更新比较频繁的应用里,页面的数据要想得到最新的结果需要重新刷新页面,但这样会产生大量的冗余数据在服务器和客户端传输,另外由于页面是同步处理的,所以在页面加载完毕之前是不能继续操作的。当客户端以固定频率向服务器发起请求的时候,服务器端的数据可能并没有更新,这样会带来很多无谓的网络传输,所以这是一种非常低效的实时方案。

websocket
WebSocket协议支持(在受控环境中运行不受信任的代码的)客户端与(选择加入该代码的通信的)远程主机之间进行全双工通信
在实现websocket连线过程中,需要通过浏览器发出websocket连线请求,然后服务器发出回应,这个过程通常称为“握手”
。在 WebSocket
API,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。在此WebSocket
协议中,为我们实现即时服务带来了两大好处:

长轮询:

  1. Header
    互相沟通的Header是很小的-大概只有 2 Bytes
  2. Server Push
    服务器的推送,服务器不再被动的接收到浏览器的请求之后才返回数据,而是在有新数据时就主动推送给浏览器。

长轮询是对定时轮询的改进和提高,目地是为了降低无效的网络传输。当服务器端没有数据更新的时候,连接会保持一段时间周期直到数据或状态改变或者时间过期,通过这种机制来减少无效的客户端和服务器间的交互。当然,如果服务端的数据变更非常频繁的话,这种机制和定时轮询比较起来没有本质上的性能的提高。

以上内容参考各种百度出的结果汇总。

威尼斯官方网站登录 1

例子:利用dwebsocket在Django中使用Websocket
1、首先安装django插件dwebsocket,pip install dwebsocket
2、编写客户端和服务端的代码
客户端:
<!DOCTYPE html>
<html>
<head>
<title>django-websocket</title>
<script
src=”;
<script type=”text/javascript”>//<![CDATA[
$(function () {
$(‘#connect_websocket’).click(function () {
if (window.s) {
window.s.close()
}
/*创建socket连接*/
var socket = new WebSocket(“ws://” + ‘127.0.0.1:8000’ +
“/app02/echo/”);
socket.onopen = function () {
console.log(‘WebSocket open’);//成功连接上Websocket
};
socket.onmessage = function (e) {
console.log(‘message: ‘ + e.data);//打印出服务端返回过来的数据
$(‘#messagecontainer’).prepend(‘<p>’ + e.data + ‘</p>’);
};
// Call onopen directly if socket is already open
if (socket.readyState == WebSocket.OPEN) socket.onopen();
window.s = socket;
});
$(‘#send_message’).click(function () {
//如果未连接到websocket
if (!window.s) {
alert(“websocket未连接.”);
} else {
window.s.send($(‘#message’).val());//通过websocket发送数据
}
});
$(‘#close_websocket’).click(function () {
if (window.s) {
window.s.close();//关闭websocket
console.log(‘websocket已关闭’);
}
});

流:

});
//]]></script>
</head>
<body>
<br>
<input type=”text” id=”message” value=”Hello, World!”/>
<button type=”button” id=”connect_websocket”>连接
websocket</button>
<button type=”button” id=”send_message”>发送
message</button>
<button type=”button” id=”close_websocket”>关闭
websocket</button>
<h1>Received Messages</h1>
<div id=”messagecontainer”>

流技术方案通常就是在客户端的页面使用一个隐藏的窗口向服务端发出一个长连接的请求。服务器端接到这个请求后作出回应并不断更新连接状态以保证客户端和服务器端的连接不过期。通过这种机制可以将服务器端的信息源源不断地推向客户端。这种机制在用户体验上有一点问题,需要针对不同的浏览器设计不同的方案来改进用户体验,同时这种机制在并发比较大的情况下,对服务器端的资源是一个极大的考验。

</div>
</body>
</html>

综合这几种方案,您会发现这些目前我们所使用的所谓的实时技术并不是真正的实时技术,它们只是在用
Ajax 方式来模拟实时的效果,在每次客户端和服务器端交互的时候都是一次 HTTP
的请求和应答的过程,而每一次的 HTTP 请求和应答都带有完整的 HTTP
头信息,这就增加了每次传输的数据量,而且这些方案中客户端和服务器端的编程实现都比较复杂,在实际的应用中,为了模拟比较真实的实时效果,开发人员往往需要构造两个
HTTP
连接来模拟客户端和服务器之间的双向通讯,一个连接用来处理客户端到服务器端的数据传输,一个连接用来处理服务器端到客户端的数据传输,这不可避免地增加了编程实现的复杂度,也增加了服务器端的负载,制约了应用系统的扩展性。

服务器端:
urls.py
# -*- coding: ut
urlpatterns = [
url(r’^home/’, views.home),
url(r’^websocket/’,views.websocket_test),
url(r’^echo/’,views.echo),
]
views.py
# -*- coding: utf-8 -*-
from dwebsocket import require_websocket,accept_websocket
import dwebsocket

HTML5 WebSocket 设计出来的目的就是要取代轮询和 Comet
技术,使客户端浏览器具备像 C/S 架构下桌面系统的实时通讯能力。 浏览器通过
JavaScript 向服务器发出建立 WebSocket
连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP
连接直接交换数据。因为 WebSocket 连接本质上就是一个 TCP
连接,所以在数据传输的稳定性和数据传输量的大小方面,和轮询以及 Comet
技术比较,具有很大的性能优势。Websocket.org
网站对传统的轮询方式和 WebSocket
调用方式作了一个详细的测试和比较,将一个简单的 Web 应用分别用轮询方式和
WebSocket
方式来实现,在这里引用一下他们的测试结果图(
):

@require_websocket
#只接受websocket请求,不接受http请求,这是调用了dwebsocket的装饰器
def websocket_test(request):
message = request.websocket.wait()
request.websocket.send(message)

威尼斯官方网站登录 2

@accept_websocket #既能接受http也能接受websocket请求
def echo(request):
if not request.is_websocket():
try:
message = request.GET[‘message’]
return HttpResponse(message)
except:
return render(request,’app02/user2.html’)
else:
for message in request.websocket:
print message
request.websocket.send(message + ‘这是你发来的。。。’.encode(‘utf-8’))
3、下面是一些方法和属性
1.request.is_websocket()

轮询和 WebSocket 实现方式的网络负载对比图

如果是个websocket请求返回True,如果是个普通的http请求返回False,可以用这个方法区分它们。

威尼斯官方网站登录,通过这张图可以清楚的看出,在流量和负载增大的情况下,WebSocket
方案相比传统的 Ajax 轮询方案有极大的性能优势。这也是为什么我们认为
WebSocket 是未来实时 Web 应用的首选方案的原因。

2.request.websocket

WebSocket协议设计用来取代使用HTTP作为传输层的双向通信技术,并从现有的基础设施(代理、过滤器、认证)受益。这些技术作为效率与可靠性的平衡而实现,因为HTTP最初并不是用于双向通信的。WebSocket尝试解决在现有HTTP基础设施的环境下现有HTTP双向通信技术的目标;像这样,它设计来工作于HTTP
80、443端口上,并支持HTTP代理和中间设施,即使这意味着增加现有环境的一些复杂性。

在一个websocket请求建立之后,这个请求将会有一个websocket属性,用来给客户端提供一个简单的api通讯,如果request.is_websocket()是False,这个属性将是None。

然后,设计并没有将WebSocket局限于HTTP,未来的实现可以在特定的端口上使用更简单的握手,而不需要重新发明整个协议。最后点是重要的,因为交互式消息的传输模式并不紧密符合标准的HTTP传输,会在一些部件上引起异常的负载。

3.WebSocket.wait()

SuperWebSocket是基于.NET开源Socket框架SuperSocket开发的,
SuperSocket所支持的大部分功能在SuperWebSocket中得到了继承。用户可通过SuperWebSocket来快速的构建可靠的,高性能的websocket服务器端应用程序。

返回一个客户端发送的信息,在客户端关闭连接之前他不会返回任何值,这种情况下,方法将返回None

和SuperSocket一样,SuperWebSocket可以控制台和windows服务的形式运行,同时它还支持直接运行在Website之内,这样更简化了用户的部署。

4.WebSocket.read()

WebSocket 协议本质上是一个基于 TCP 的协议。为了建立一个 WebSocket
连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的
HTTP 请求不同,包含了一些附加头信息,其中附加头信息”Upgrade:
WebSocket”
表明这是一个申请协议升级的 HTTP
请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的
WebSocket
连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。

如果没有从客户端接收到新的消息,read方法会返回一个新的消息,如果没有,就不返回。这是一个替代wait的非阻塞方法

下面我们来详细介绍一下 WebSocket 规范,WebSocket
协议有两部分:握手和数据传输。

5.WebSocket.count_messages()

客户端发出的握手信息:

返回消息队列数量

GET /chat HTTP/1.1

6.WebSocket.has_messages()

Host: server.example.com

如果有新消息返回True,否则返回False

Upgrade: websocket

7.WebSocket.send(message)

Connection: Upgrade

向客户端发送消息

Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

8.WebSocket.__iter__()

Origin:

websocket迭代器

Sec-WebSocket-Protocol: chat, superchat

参考链接:

Sec-WebSocket-Version: 13

服务器端返回的握手信息:

HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Sec-WebSocket-Protocol: chat

客户端握手的引导行遵从(HTTP)Request-Line格式,服务器发出的引导行遵从(HTTP)Status-Line格式。在两种情况下,引导行后面跟着一组未排序的头域。额外的头域也可能出现,如cookie。头的格式和解析在RFC2616定义。

一旦客户端和服务器都发送了他们的握手,如果握手成功,传输数据部分开始。

在实际的开发过程中,为了使用 WebSocket 接口构建 Web
应用,我们首先需要构建一个实现了 WebSocket
规范的服务器,服务器端的实现不受平台和开发语言的限制,只需要遵从
WebSocket 规范即可,目前已经出现了一些比较成熟的 WebSocket
服务器端实现,比如:

  • Kaazing WebSocket Gateway — 一个 Java 实现的 WebSocket Server
  • mod_pywebsocket — 一个 Python 实现的 WebSocket Server
  • Netty —一个 Java 实现的网络框架其中包括了对 WebSocket 的支持
  • node.js —一个 Server 端的 JavaScript 框架提供了对 WebSocket 的支持
  • SuperWebSocket –一个.NET/Mono 实现的WebSocket Server(本文的主角)

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章