WebSocket 的定义?WebSocket是HTML5下一种全双工通讯协议。在创建链接后,WebSocket服务器端和客户端都能主动的向对方发送和接收数据,就像Socket同样。javascript
WebSocket 的由来?众所周知,HTTP协议有“无链接”、“不可靠”、“尽最大努力”的特色。WebSocket的出现能够当作是HTTP协议为了支持长链接所打的一个大补丁。首先,由 IETF 制定发布了WebSocket 协议。后来,HTML5为了在Web端支持WebSocket协议,由W3C 发布了一整套WebSocket API。其次,WebSocket主要用于Web端,对于非Web部分的意义不大(毕竟直接使用TCP就行了)。所以,在广义上,Websocket 也经常被人称为是HTML5 下的通讯协议。css
HTTP 和 WebSocket 的区别?前端
一、HTTP 和 WebSocket 是两种不一样的协议,可是HTTP负责了创建WebSocket的链接。java
二、HTTP 请求以 http:// 或 https:// 开始,WebSocket 请求通常以ws:// 或 wss:// 开始。git
三、全部浏览器都支持 HTTP 协议,WebScoket 能够会遇到不支持的浏览器(可经过SockJS解决)github
四、HTTP长链接中,每次数据交换除了真正的数据部分外,服务器和客户端还要大量交换HTTP header,信息交换效率很低。Websocket协议经过第一个request创建了TCP链接以后,以后交换的数据都不须要发送 HTTP header就能交换数据。web
能够看看知乎上的这个回答,解释的挺生动的:https://www.zhihu.com/question/20215561spring
先来看看客户端如何创建起WebSocket 的链接。首先,咱们使用 new WebSocket(url) 建立一个WebSocket 的实例对象;而后,使用这个实例对象创建WebSocket的事件处理功能,onopen、onmessage、onclose 和 onerror 事件,分别对应着 打开链接、接收消息、关闭链接 和 异常处理 事件。api
/*WebSocket*/ var url = 'ws://localhost:8080/marco2'; var sock = new WebSocket(url); sock.onopen = function (ev) { console.log("正在创建链接..."); sayMarco(); }; sock.onmessage = function (ev) { console.log("接收并处理消息:" + ev.data); if (count == 10) { sock.close(); } setTimeout( function () { sayMarco(); count++; }, 2000); }; sock.onclose = function (ev) { console.log("链接关闭..."); }; sock.error = function (ev) { console.log("链接异常"); }; function sayMarco() { console.log('Sending Marco !'); sock.send("Marco!") }
接下来看看服务端这边如何创建起WebSocket的服务:浏览器
<!--WebSocket--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>4.3.13.RELEASE</version> </dependency> <!--辅助包--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.8.10</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.8.10</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.8.10</version> </dependency>
有两种方案能够创建起WebSocket服务,一种是基于Spring 的 spring-websocket,一种是基于 java 的 websocket-api。
WebSocketHandler 接口定义了服务端处理WebSocket消息要作的一系列事情。相比直接实现WebSocketHandler,更为简单的方法是扩展AbstractWebSocketHandler,这是WebSocketHandler的一个抽象实现。固然根据处理消息的类型,还能够选择继承TextWebSocketHandler(文本类消息)、BinaryWebSocketHandler(二进制消息)等...
public class MarcoHandler_2 extends AbstractWebSocketHandler { private static final Logger LOGGER = LoggerFactory.getLogger(MarcoHandler_2.class); @Override public void afterConnectionEstablished(WebSocketSession session) { LOGGER.info("WebSocket 链接创建......"); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { LOGGER.info("接收到消息:" + message.getPayload()); Thread.sleep(2000); //发送文本消息 session.sendMessage(new TextMessage("Polo!")); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus){ LOGGER.info("WebSocket 链接关闭......"); } }
websocket-api 提供了一种基于注解、更为简单明了的方式处理WebSocket消息。美中不足的是它须要依赖 javax.websocket-api.jar。
① pom依赖
<dependency> <groupId>javax.websocket</groupId> <artifactId>javax.websocket-api</artifactId> <version>1.1</version> <scope>provided</scope> </dependency>
② WebSocket服务
/** * Created by XiuYin.Cui on 2018/5/2. * * 基于注解方式的WebSocket 控制器 */ @ServerEndpoint("/ws") public class WsController { private static final Logger LOGGER = LoggerFactory.getLogger(WsController.class); @OnOpen public void onOpen(){ LOGGER.info("链接创建"); } @OnClose public void onClose(){ LOGGER.info("链接关闭"); } @OnMessage public void onMessage(String message, Session session){ try { LOGGER.info("接收到消息:" + message); Thread.sleep(2000); session.getBasicRemote().sendText("polo"); //发送消息 } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } @OnError public void onError(Session session, Throwable throwable){ throw new IllegalArgumentException(throwable); } }
如今,已经有了消息处理器类,咱们必需要对其进行配置,这样Spring才能将消息转发给它。在Spring的Java配置中,这须要在一个配置类上使用@EnableWebSocket,并实现WebSocketConfigurer接口。
像全部HTTP请求同样,咱们须要将WebSocket服务暴露成一个供客户端访问的url 地址。依旧有两种方式,配置类方式 和 XML方式:
@Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { /** * * @param registry 该对象能够调用addHandler()来注册信息处理器。 */ @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(marcoHandler_2(),"/marco2") .addInterceptors(webSocketHandshakeInterceptor()) //声明拦截器 .setAllowedOrigins("*"); //声明容许访问的主机列表 } @Bean public MarcoHandler_2 marcoHandler_2(){ return new MarcoHandler_2(); } @Bean public WebSocketHandshakeInterceptor webSocketHandshakeInterceptor(){ return new WebSocketHandshakeInterceptor(); } }
<websocket:handlers> <websocket:mapping handler="marcoHandler_1" path="/marco1"/> </websocket:handlers>
既然已经有了WebSocket API 为何还要有SockJS呢?
一、WebSocket 是一个较新的协议规范,在Web浏览器和应用服务器上可能没有获得一致的支持。
二、防火墙代理一般会限制全部除HTTP之外的流量。它们可能不支持或者尚未配置容许进行WebSocket 通讯。
SockJS 又是什么呢?
SockJS是WebSocket技术的一种模拟,在表面上,它尽量对应WebSocket API,可是在底层它很是智能。SockJS会优先选用WebSocket,可是若是WebSocket不可用的话,它将会从以下的方案中挑选最优的可行方案:
接下来让咱们看看SockJS 的使用和WebSocket 有什么差别?
要在客户端使用SockJS,须要确保加载了SockJS客户端库。
<script type="text/javascript" src="http://cdn.bootcss.com/sockjs-client/1.1.1/sockjs.js"></script>
SockJS所处理的URL是“http://”或“https://”模式,而不是“ws://”和“wss://”。
var url = 'http://localhost:8080/marcoSockJS'; var sock = new SockJS(url);
服务端这边只要在创建映射的时候加上SockJS的支持便可:
@Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { /** * * @param registry 该对象能够调用addHandler()来注册信息处理器。 */ @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { //声明启用SockJS链接,若是前端还用 new WebSocket(url); 会报:Error during WebSocket handshake: Unexpected response code: 200 registry.addHandler(marcoHandler_2(), "/marcoSockJS") .setAllowedOrigins("*") ////声明容许访问的主机列表 .withSockJS(); } @Bean public MarcoHandler_2 marcoHandler_2(){ return new MarcoHandler_2(); } }
<websocket:handlers> <websocket:mapping handler="marcoHandler_1" path="/marco1"/> <websocket:sockjs/> <!--声明启用SockJS功能--> </websocket:handlers>
效果展现:
演示源码下载连接:https://github.com/JMCuixy/SpringWebSocket/tree/developer