黑马程序员技术交流社区

标题: 【上海校区】记录关于websocket的原理和使用 [打印本页]

作者: 陈泽    时间: 2019-3-25 14:13
标题: 【上海校区】记录关于websocket的原理和使用
本帖最后由 陈泽 于 2019-3-25 14:19 编辑

什么是websocket
    WebSocket是一种在单个TCP连接上进行全双工通讯的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。Websocket是一个持久化的协议,相对于HTTP这种非持久的协议来说的。
举个例子:
[AppleScript] 纯文本查看 复制代码
HTTP的生命周期通过 Request 来界定,也就是发送一次 Request,收到一次 Response ,那么在 HTTP1.0 中,这次HTTP请求就结束了
在HTTP1.1中进行了改进,使得有一个keep-alive,也就是说,在一个HTTP连接中,可以发送多个Request,接收多个Response。但是请记住 Request = Response , 在HTTP中永远是这样,也就是说一个request只能有一个response。而且这个response也是被动的,不能主动发起。
而对于websocket来说,在HTTP的握手基础上建立起链接,服务器端可以主动的向客户端发送数据。

为什么要使用websocket
    现在,很多网站为了实现页面上的数据更新,都是通过ajax技术轮询去服务器拉取数据。轮询是在特定的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
而比较新的技术去做轮询的效果是Comet。Comet技术又可以分为长轮询和流技术。长轮询改进了上述的轮询技术,减小了无用的请求。它会为某些数据设定过期时间,当数据过期后才会向服务端发送请求;这种机制适合数据的改动不是特别频繁的情况。流技术通常是指客户端使用一个隐藏的窗口与服务端建立一个HTTP长连接,服务端会不断更新连接状态以保持HTTP长连接存活;这样的话,服务端就可以通过这条长连接主动将数据发送给客户端;流技术在大并发环境下,可能会考验到服务端的性能。这两种技术都是基于请求-应答模式,都不算是真正意义上的实时技术;它们的每一次请求、应答,都浪费了一定流量在相同的头部信息上,并且开发复杂度也较大。
在这种情况下,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
Websocket使用ws或wss的统一资源标志符,类似于HTTPS,其中wss表示在TLS之上的Websocket。
   如:
         ws://example.com/wsapiwss://secure.example.com/
        Websocket使用和 HTTP 相同的 TCP 端口,可以绕过大多数防火墙的限制。默认情况下,Websocket协议使用80端口;运行在TLS之上时,默认使用443端口。
        WebSocket 目前由 W3C 进行标准化。WebSocket 已经受到 Firefox 4、Chrome 、Opera 10.70 以及 Safari 5 等浏览器的支持。

一个典型的websocket的握手请求
GET / HTTP/1.1Upgrade: websocketConnection: UpgradeHost: example.comOrigin: http://example.comSec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==Sec-WebSocket-Version: 13HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=Sec-WebSocket-Location: ws://example.com/字段说明
如何使用websocket
关于如何在Python后端使用websocket的技术有多种方式,可以参考这篇文章《python使用websocket的几种方式》
我们的项目使用的是Django的框架,我这次的实践主要围绕Django 的websocket插件 dwebsocket 展开记录。源码地址
安装dwesocket
话不多说, pip大法。
pip install dwesocket使用
如果希望一个view视图既可以处理HTTP请求,也可以处理websocket请求,只需要将这个view函数用装饰器 @accept_websocket 包裹即可。也可以使用 @require_websocket 装饰器,这样的话这个视图只允许接受websocket请求,会拒绝正常的HTTP请求。
如果你希望在应用程序中为所有的url提供websocket请求支持,则可以使用中间件。只需要将dwebsocket.middleware.websocketmiddleware 添加到设置中的的 MIDDLEWARE_CLASSES 中。 (如果没有需要自己定义,不定义会报错,这个有点尴尬,对于这一点的优化,我已经对主库提了一个Pull Request,希望作者还在维护....)
MIDDLEWARE_CLASSES = ['dwebsocket.middleware.WebSocketMiddleware']
如果允许每个单独的视图接受websocket请求,在settings中设置 WEBSOCKET_ACCEPT_ALL 为 True.
WEBSOCKET_ACCEPT_ALL = True
接口和属性实践例程
从客户端接收一条消息,将该消息发送回客户端并关闭连接(通过视图返回):
from dwebsocket import require_websocket@require_websocketdef echo(request):    message = request.websocket.wait()    request.websocket.send(message)
我们也可以让服务端不自动关闭连接,下面的例程中,服务器端会将客户端发来的消息转为小写发送回去,并增加了普通的HTTP请求的响应,也做同样操作返回:
from django.http import HttpResponsefrom dwebsocket import accept_websocketdef modify_message(message):    return message.lower()@accept_websocketdef lower_case(request):    if not request.is_websocket(): # 普通HTTP请求        message = request.GET['message']        message = modify_message(message)        return HttpResponse(message)    else: # websocket请求        for message in request.websocket:            message = modify_message(message)            request.websocket.send(message)

改变dwebsocket后端
目前dwebsocket支持两种后端,分别是 default 的和 uwsgi。
默认 default 支持 Django自身的开发服务器, eventlent, gevent, 和gunicore。
如果你想使用uwsgi后端,在settings.py文件中添加 WEBSOCKET_FACTORY_CLASS:
WEBSOCKET_FACTORY_CLASS = 'dwebsocket.backends.uwsgi.factory.uWsgiWebSocketFactory'
运行 uwsgi :
uwsgi --http :8080 --http-websockets --processes 1 \--wsgi-file wsgi.py--async 30 --ugreen --http-timeout 300

websocket的优缺点


优点缺点
下面这些出自知乎,优点鸡肋的缺点,就是对开发者技术要求高点应该不算缺点,新的技术总有个普及的过程。
对前端开发者:
对于后端开发者:










欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2