websoket原理和实战
概述
项目包结构
两个包:
com.javasea.web.websocket.springb.websocket
使用实现WebSocketConfigurer
接口的方式实现
com.javasea.web.websocket.springb.websocket2
通过注解@ServerEndpoint
方式实现
场景引用
场景:页面需要实时显示被分配的任务,页面需要实时显示在线人数。
思考:像这样的消息功能怎么实现? 如果网页不刷新,服务端有新消息如何推送到浏览器?
解决方案,采用轮询的方式。即:通过js不断的请求服务器,查看是否有新数据,如果有,就获取到新数据。
这种解决方法是否存在问题呢?
当然是有的,如果服务端一直没有新的数据,那么js也是需要一直的轮询查询数据,这就是一种资源的浪费。
那么,有没有更好的解决方案? 有!那就是采用WebSocket技术来解决。
什么是WebSocket?
WebSocket 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成。 WebSocket是真正实现了全双工通信的服务器向客户端推的互联网技术。 它是一种在单个TCP连接上进行全双工通讯协议。Websocket通信协议与2011年倍IETF定为标准RFC 6455,Websocket API被W3C定为标准。
什么叫做全双工和半双工?
比如对讲机,说话的时候就听不到对方说话,那么就是半双工。
我们打电话的时候说话的同时也能听到对方说话,就是全双工。
http与websocket的区别
http协议是短连接,因为请求之后,都会关闭连接,下次重新请求数据,需要再次打开链接。
WebSocket协议是一种长链接,只需要通过一次请求来初始化链接,然后所有的请求和响应都是通过这个TCP链接进行通讯。
浏览器支持情况
服务器支持情况:Tomcat 7.0.47+以上才支持。
快速入门
创建项目
配置pom.xml
- 集成javaee
1 | 复制代码 <dependency> |
- 配置tomcat插件
1 | 复制代码 <plugin> |
之后启动服务
只需要在maven中直接运行即可。
pom的详细配置如下:
1 | 复制代码<?xml version="1.0" encoding="UTF-8"?> |
websocket的相关注解说明
@ServerEndpoint("/websocket/{uid}")
申明这是一个websocket服务
需要指定访问该服务的地址,在地址中可以指定参数,需要通过{}进行占位@OnOpen
用法:public void onOpen(Session session, @PathParam(“uid”) String uid) throws
IOException{}
该方法将在建立连接后执行,会传入session对象,就是客户端与服务端建立的长连接通道
通过@PathParam获取url申明中的参数@OnClose
用法:public void onClose() {}
该方法是在连接关闭后执行@OnMessage
用法:public void onMessage(String message, Session session) throws IOException {}
客户端消息到来时调用,包含会话Session,根据消息的形式,如果是文本消息,传入String类型参数或者Reader,如果是二进制消息,传入byte[]类型参数或者InputStream。
message:发来的消息数据
session:会话对象(也是通道)
发送消息到客户端
用法:session.getBasicRemote().sendText(“你好”);
通过session进行发送。
实现websocket服务
1 | 复制代码@ServerEndpoint("/websocket/{uid}") |
maven中启动tomcat:
1 | 复制代码mv tomcat7:run |
也可以用上文中在IDE中直接启动。
测试
一共有三种测试方式,直接js脚本方式、chrome插件方式或者通过在线工具进行测试:
- 直接js脚本方式,直接用如下代码进行测试:
1 | 复制代码var socket; |
浏览器随便打开一个网页,然后粘贴到console下,回车即可
- chrome插件方式,需要安装chrome插件,Simple WebSocket Client:
chrome.google.com/webstore/de…
- 在线工具进行测试(推荐):www.websocket-test.com/
我一直测试失败,还没找到原因。下文整合springboot的测试成功。
编写js客户端
在webapp下编写两个html文件
websocket.html
内容如下
1 | 复制代码<!DOCTYPE html> |
websocket2.html
内容如下
1 | 复制代码<!DOCTYPE HTML> |
在浏览器请求http://localhost:8082/websocket2.html
emmm,失败的,还没找到原因,下文整合springboot,测试是成功的。
整合springboot
使用springboot内置tomcat时,就不需要引入javaee-api了,spring-boot已经包含了。
springboot的高级组件会自动引用基础的组件,像spring-boot-starter-websocket就引入了spring-boot-starter-web和spring-boot-starter,所以不要重复引入
springboot已经做了深度的集成和优化,注意是否添加了不需要的依赖、配置或声明。由于很多讲解组件使用的文章是和spring集成的,会有一些配置。在使用springboot时,由于springboot已经有了自己的配置,再这些配置有可能导致各种各样的异常。
pom.xml配置
1 | 复制代码<?xml version="1.0" encoding="UTF-8"?> |
springboot有两种方式实现websocket
- 通过注解
@ServerEndpoint
方式实现
webSocket核心是@ServerEndpoint
这个注解。这个注解是Javaee标准里的注解,tomcat7以上已经对其进行了实现,如果是用传统方法使用tomcat发布的项目,只要在pom文件中引入javaee标准即可使用。
快速入门中的例子就是通过@ServerEndpoint来实现的WebSocket服务,在整合springboot的时候需要额外配置Config类,创建一个ServerEndpointExporter();
1 | 复制代码@Configuration |
- 使用实现
WebSocketConfigurer
接口的方式实现
下文就是这种方式的实现
编写WebSocketHandler
在Spring中,处理消息的具体业务逻辑需要实现WebSocketHandler接口。
1 | 复制代码package com.javasea.web.websocket.springb.websocket; |
编写配置类来实现WebSocket服务
1 | 复制代码package com.javasea.web.websocket.springb.websocket; |
编写启动类
1 | 复制代码package com.javasea.web.websocket.springb; |
测试
在线进行测试,url:ws://localhost:8080/ws
用上文的html页面也可以测试的,修改地址为
ws://localhost:8080/ws
然后在文件夹下直接用浏览器打开即可。
添加拦截器
1 | 复制代码package com.javasea.web.websocket.springb.websocket; |
将拦截器添加到websocket服务中:
就是在上文的config中添加
addInterceptors(this.myHandshakeInterceptor);
。
1 | 复制代码package com.javasea.web.websocket.springb.websocket; |
测试拦截器
在MyHandler
类afterConnectionEstablished
方法下输出获取到的uid
。
1 | 复制代码@Override |
连接websocket服务 ws://localhost:8080/ws
,console输出:
1 | 复制代码握手成功啦。。。。。。 |
说明测试成功。
项目地址
github地址:github.com/longxiaonan…
参考
本文转载自: 掘金