内容简介:WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
原理
WebSocket是一种在单个TCP连接上进行全双工通信的协议。
WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。
在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
http协议中有keep-alive,只是把多个HTTP请求合并到一个tcp连接里进行传输, Websocket
是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范,也就是说它是HTTP协议上的一种补充。
Websocket协议
HTTP协议中,HTTP的生命周期通过 Request
来界定,一个 Request对应
一个 Response,客户端发起一个Request,在收到Response之后,一次HTTP请求生命周期结束。而且必须客户端先发送一个Request,服务端才能给客户端发送Response,服务器端属于被动的,不能主动发起。WebSocket的基于长连接,可以双向通信,生命周期如下:
有如下特点:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信。
(6)协议标识符是 ws
(如果加密,则为 wss
),服务器网址就是 URL。
WebSocket借用HTTP协议来完成首次握手,随后使用WebSocket进行通信。
HTTP握手请求如下:
GET /chat HTTP/1.1
Host:server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin:example.com
Upgrade: websocket Connection: Upgrade 表示协议升级为websocket协议。
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== 客户端也就是浏览器或者其他终端随机生成一组16位的随机base64编码的串
Sec-WebSocket-Protocol: chat, superchat 使用协议
Sec-WebSocket-Version: 13 当前使用协议的版本号
握手返回如下:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
状态码和描述 101 Switching Protocols表示协议切换成功
Upgrade: websocket Connection: Upgrade 表示协议升级成功为websocket 复制代码
Sec-WebSocket-Accept
这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key
Sec-WebSocket-Protocol
则是表示最终使用的协议
前端代码:
var ws = new WebSocket(" wss://echo.websocket.org ");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};
不支持WebSocket
不支持WebSocket的场景有:
- 浏览器不支持
- Web容器不支持,如tomcat7以前的版本不支持WebSocket
- 防火墙不允许
- Nginx没有开启WebSocket支持
基于 SockJS 的 WebSocket
在不支持WebSocket的情况下,也可以很简单地实现WebSocket的功能的,方法就是使用 SockJS。它会优先选择WebSocket进行连接,但是当服务器或客户端不支持WebSocket时,会自动在 XHR流、XDR流、iFrame事件源、iFrame HTML文件、XHR轮询、XDR轮询、iFrame XHR轮询、JSONP轮询 这几个方案中择优进行连接。
服务端
在启动WebSocket的配置中,你需要做的所有事情就是加上 withSockJS()
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
// withSockJS 声明启用支持 sockJS
webSocketHandlerRegistry.addHandler(marcoHandler(), "/echo").withSockJS();
客户端
在客户端需要引入SockJS库,然后把 new WebSocket(url); 替换成 new SockJS(url);
SockJS类和WebSocket类是兼容的,所以可以直接替换
<script type="text/javascript" src="/resources/js/sockjs-1.0.0.min.js"></script>
var sock = new SockJS(url);
应用
以下是一个基于spring、sockjs的一个样例
- 引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId></dependency>复制代码
- 添加配置
@Configuration@EnableWebSocketMessageBrokerpublic class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) {复制代码
registry .addEndpoint("/websocket/tracker") .setAllowedOrigins("*") .withSockJS();复制代码
} @Override public void configureMessageBroker(MessageBrokerRegistry config) {复制代码
config.enableSimpleBroker("/topic", "/user"); config.setUserDestinationPrefix("/user"); config.setApplicationDestinationPrefixes("/app");复制代码
}} 复制代码
1)@EnableWebSocketMessageBroker注解用于开启使用STOMP协议来传输基于代理(MessageBroker)的消息,这时候控制器(controller)开始支持@MessageMapping,就像是使用@requestMapping一样。
2).addEndpoint("/websocket/tracker") 注册一个 Stomp 端点,客户端连接服务端是使用;.setAllowedOrigins("*")表示允许跨域;.withSockJS()表示指定使用SockJS协议。SockJs是一个WebSocket的通信js库,Spring对这个js库进行了后台的自动支持,如果使用它不需要进行过多配置。
3)config.enableSimpleBroker("/topic", "/user") 启用一个简单的message broker并配置一个或多个前缀来过滤针对代理的目的地,客户端订阅这个地址,服务端可以向改地址发送消息;
config.setApplicationDestinationPrefixes("/app");
- 提供接口
@MessageMapping("/hello") @SendTo("/topic/greetings") public Greeting greeting(HelloMessage message) throws Exception { System.out.println("收到:" + message.toString() + "消息"); return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!"); }复制代码
1)@MessageMapping用于设置URL映射地址,浏览器向服务器发起请求,需要通过该地址,客户端发送消息时,需要访问/app/hello。
2)@SendTo("/topic/greetings") 设置目的地,服务器想客户端发送消息,这里的目的地是站在服务端的角度对客户端而言。客户端也需要设置相同的地址,而且必须使用/topic前戳,前面也已经讲述。
- 发送消息
SimpMessagingTemplate.convertAndSendToUser(String user, String destination, Object payload)复制代码
SimpMessagingTemplate.convertAndSend(D destination, Object payload)复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Git 原理入门
- 黑客入门——手机wifi定位原理
- Vue 服务端渲染原理及入门
- Apache Kylin 入门 2 - 原理与架构
- Etcd Raft 使用入门及原理解析
- DDOS入门介绍(二):常见攻击手段与原理
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。