springboot2整合WebSocket入门实战
一、问题描述
最近刚好有一个需要,就是需要服务端推送消息到客户端,解决方案第一个想到的便是前端轮询服务器,查询服务器是否有请求。对于这种方法,优点是简单,但缺点也十分明显,那就是十分耗费服务器资源。因此在这里介绍了第二种方法,使用webSocket。
二、websocket与http 区别
http协议是用在应用层的协议,他是基于tcp协议的,http协议建立链接也必须要有三次握手才能发送信息。http链接分为短链接,长链接,短链接是每次请求都要三次握手才能发送自己的信息。即每一个request对应一个response。长链接是在一定的期限内保持链接。保持TCP连接不断开。客户端与服务器通信,必须要有客户端发起然后服务器返回结果。客户端是主动的,服务器是被动的。
WebSocket是HTML5中的协议, 他是为了解决客户端发起多个http请求到服务器资源浏览器必须要经过长时间的轮训问题而生的,他实现了多路复用,他是全双工通信。在webSocket协议下客服端和浏览器可以同时发送信息。服务器也可以主动推送消息给客户端。
三、springboot整合WebSocket
1、maven依赖
1 | <dependency> |
2、配置WebSocketConfig
1 |
|
3、设置WebSocketServer(重点)
直接@ServerEndpoint("/wsserver/{userId}")
、@Component
启用即可,然后在里面实现@OnOpen
开启连接,@onClose
关闭连接,@onMessage
接收消息等方法
1 |
|
注意:如果项目使用了nginx反向代理,则需要在nginx的配置文件的location/
位置处添加
1 | proxy_http_version 1.1; |
4、前端页面调用
1 |
|
5、运行结果
在这里我开了两个界面,userId分别是1和2,这里我在1发送了如下json串,这会经过服务器自动转发到仍然在线的2。同时我们可以查看到服务端可以统计当前在线人数,还打印出了转发的报文
1 | { |
简单的实战到此为止,再次基础上可以修改很多功能啦~
四、SpringBoot整合Netty
1、导入依赖
1 | <dependency> |
2、配置自定义handelr
通道处理器
1 | public class MyChannelHandler { |
websocket处理器
1 | /** |
3、配置心跳包
1 | /** |
4、配置Netty服务器
1 |
|
5、前端测试验证
和上面的前端一样,修改部分即可,websocket = new WebSocket("ws://localhost:8080/ws?ss=1234");
或websocket = new WebSocket("ws://localhost:8080/ws");
或者WS在线测试网站
五、WebSocket注意事项
1、问题一
1.1 问题描述
在websocket服务中,有时候可能需要加其他类,比如我需要VideoService
类,这时候使用@Autowired
自动注入,但是运行的时候报错java.lang.NullPointerException
1 |
|
1.2 原因与解决方法
这个线程是tomcat启动的,在这个tomcat启动的线程中是不能使用spring容器提供的@Autowired
的单例bean。
如果不是static,这个repository就是null。在这个线程中也没有办法从spring容器中取到这个bean,所以只能把这个bean设置为static,这样这个单例bean就脱离了spring容器的限制,可以在所有线程中使用了
1 | /** |
另一个思路:实现BeanFactoryAware,这样可以通过注入的BeanFactory拿到这个bean,应该也是可行的
2、问题二
2.1 问题描述
刚开始的时候用户退出只将Session从Map中取出,发现用户退出了,但是用户仍然可以发送消息,经过测试才发现单纯从Map去除并不会断开session连接,需要显示调用session.close()
才能真正断开连接
3、问题三
3.1 问题描述
配置了Nginx的proxy_read_timeout
参数后,websocket会进行缓存,当websocket再次进行onOpen()
重连时,websocket仍然会检测到原来的连接(即session),直到proxy_read_timeout
参数过期;同时客户端发送心跳包给websocket连接,会使得proxy_read_timeout
参数延续;或者websocket手动关闭
4、问题四
4.1 问题描述
http的session对象和websocket的session是不一样的。http的时候,是javax.servlet.http.HttpSession
,而websocket的时候javax.websocket.Session
。
http的session一般用于保存用户信息,根据用户,http请求的时候携带Cookie:JSESSIONID
,进行区分,实现多例。http的session的getId()就是JSESSIONID,比如BD70D706E4B975EA5CE7418152D3F8DC
这种。而websocket的Session则有很多用处,保存信息,发送请求,可以说websocket前后端交互用的变量和方法,都保存在websocket的Session里。同时,websocket的Session是根据前端创建连接多例的,也就是说,前端每new WebSocket进行open一次,就创建一个websocket的Session。websocket的Session的getId()是从1开始递增的序列。
六、未来与展望
websocket对于并发并不是很好,一般使用netty,下面是一些参考链接
SpringBoot(23) 集成socket.io服务端和客户端实现通信