websocket官方文档,websocket 应用
如何在Spring中配置Websocket
Java 实现方法
在 Spring 端可以有以下几种方法使用 WebSocket
1. 使用 Java EE7 的方式
2. 使用 Spring 提供的接口
3. 使用 STOMP 协议以及 Spring 的 MVC
第三种方式见 Spring 的官方文档, 基于 webSocket, 使用 Simple Text Oriented Message Protocol(STOMP) 协议:Using WebSocket to build an interactive web application
STOM 协议工作在 Socket 之上, 类似于 HTTP 协议, 为面向于文本消息的中间件而设计, 是一种语言无关的协议, 符合该协议的 client 和 broker 之间都能通信, 无论是使用何种语言开发.
STOM 协议介绍
这里我将着重介绍使用 Spring 提供的接口开发的方式.
主要分为以下几个类, 第一个是 WebSocket 连接建立前的拦截类 HandshakeInterceptor, 类似于 Spring MVC 的 HandlerInteceptor, 第二个 WebSocket 的处理类, 负责对生命周期进行管理, 第三个是配置类, 将 websocket 请求与对应的 handler 类进行映射.
**1.HandshakeInterceptor
2.WebSocketHandler
3.WebSocketConfigurer**
django websocket
做个比喻, 如果说A是服务端, B是客户端, 现在要在A家里吃火锅, 虽然A说你人来就行, 但是B心想总得带点东西过去, 于是去了市场.
先到了蔬菜店, B想买点菠菜, 但又怕A家里已经有了, 于是给A打电话
B: "我带点菠菜过去吧?"
A: "好"
然后挂断. 过一会儿到了水产区
B: "我带点虾过去吧?"
A: "不用"
...如此反复多了之后A突然发现自己确实少准备了一些东西, 于是A给主动给B打了电话
A: "我忘准备蘸料了, 你买点, 然后先别挂掉"
...
A: "再买瓶酒"
...
这就是websocket了
django当让也提供对websocket的支持, 虽然这似乎不是他更擅长的东西. 我们可以通过channels实现websocket连接
诸如上述例子的场景都是合适的场景
举例来说的话比如聊天室, 每个人发送的消息都要实时显示在别人的屏幕上.
比如说数据监控, 波动状态也要实时的呈现在屏幕上, 而不是依赖于使用者自己刷新.
需要安装 channels , asgi_redis , asgiref , channels_redis . 后三个未必都需要装, 记不太清了, 总之安装过程都在channels的使用文档上.
INSTALL_APPS 中需要加上 "channels" , 需要注意的是因为这是一个list, 是有先后顺序的, 最好把它加在第一个.
这里我们的channel通过redis实现, 要在 settings.py 中配置
这里还有点小坑, 官方文档里的hosts不是这种格式, 是 "uri" 这种模式, 但是如果你在设置redis密码时机智的设置了特殊符号( '#$%' 这种), 你就会发现redis的 uri 直接就用不了了, 期间尝试各种方法, 转义什么的也试了都不行, 然后去github上开了个issue, 结果作者说我们是通过 aioredis 连接的, 你去找他们的文档吧....
然后就找到了这种方式.
常规的WSGI不支持websocket, 所以还需要配置ASGI
ASGI_APPLICATION = 'project.routing.application'
同wsgi的配置一样, 这是指向 project 文件夹下 routing.py 文件的 application
这里建议大家跟这官方教程的Tutorial走一遍. 有个比较悲剧的地方就是网上可以搜到许多channels使用指南, 大多都是搭个简易聊天室什么的, 然而你用起来可能发现存在各种报错, 因为channels升了2.0之后更改了一些方法, 而那些教程里基本全都是1.x的版本.
简单说下, 首先 startapp 叫 chat , 假如这里我们没有进行前后端分离, 里面有 templates , 两个 html : index 和 room 分别对应首页和某一个聊天室
新建 consumers.py 来写 websocket 方法
如上, connect 和 disconnect 含义分别如函数名. 因为是聊天室, 所以同一个聊天室内的人应该消息共享, 用 room_group_name 来区分所在的频道.
receive 和 chat_message 是对消息的处理. 当一个用户发送消息时, 前端把消息通过websocket发送过来, receive 收到消息提取关键内容, 通过 chat_message 发送给组内的所有连接. 这时保持连接的所有组内人员都会收到这条消息推送, 前端收到推送再显示在屏幕上.
定义websocket的地址
类似于 django 的 url ( consumers.py 就类似于 views.py ), 同级新建 routing.py
统一用ws/来区分websocket的连接
剩下常规的页面配置和django一样
views.py :
urls.py :
注意: 如果网站是http, 连接使用ws, 如果是https要修改成wss
剩下的自己找资料吧, 笔者对前端了解的不多
本地的话 runserver 就好了, 但是在线上还是得更改启动方式应对高并发.
传统的 uwsgi 不支持 websocket .
gunicorn 好像可以同时支持 websocket , 但是性能不太ok
这里我们用 daphne
这里需要额外开个服务, 专门负责处理websocket.
ingress中要配置路由跳转
WebSocket协议-原理篇
本篇文章主要讲述以下几点:
WebSocket协议分为两部分:握手和数据传输
下面通过客户端和服务端交互的报文对比WebSocket通讯与传统HTTP的不同点,主要关注握手阶段。
根据上面的例子,运行之后,new WebSocket实例化一个新的WebSocket客户端对象,请求WebSocket URL为 ws://localhost:8000 的服务器,打开控制台的NetWork,客户端WebSocket对象会自动解析并识别为WebSocket请求,连接服务端端口,执行双方握手过程,来自客户端握手发送数据格式如下:
至此,HTTP已经完成它所有工作,接下来就是完全按照Websocket协议进行了。
通过查看WebSocket的原理,与HTTP对比,得出结论:
HTTP长连接中,每次数据交换除了真正的数据部分外,服务器和客户端还要大量交换HTTP header,信息交换效率很低。Websocket协议通过第一个请求建立了TCP连接之后,之后交换的数据都不需要发送 HTTP header就能交换数据,这显然和原有的HTTP协议有区别,所以它需要对服务器和客户端都进行升级才能实现(主流浏览器都已支持HTML5)。此外还有 multiplexing、不同的URL可以复用同一个WebSocket连接等功能。这些都是HTTP长连接不能做到的。
我们在使用WebSocket协议时通常不会使用它的API来实现,而是借助于Socket.io,Socket.io是一个WebSocket库,包括客户端的js和服务端的nodejs,它的目标是构建可以在不同浏览器和移动设备上使用的实时应用。它会自动根据浏览器从WebSocket、AJAX长轮询等各种方式中选择最佳的方式来实现网络实时应用,也就是说如果浏览器对WebSocket兼容性差,Socket.io会自动选择最佳方式实现实时通信,非常方便和人性化。
Socket.io 官方文档:
WebSocket兼容几乎所有现代浏览器,IE 10+ Edge Firefox 4+ Chrome 4+ Safari 5+ Opera 11.5+
socket.io对浏览器做了很好的兼容。
下一篇讲述Socket.io客户端API
参考文档: