什么是WebSocket?
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
WebSocket使服务器和客户端交互数据时变的更加简单,允许服务端向客户端推送数据,在WebSocket API中,服务器和浏览器只需进行一次握手(连接)就可以创建持久性的连接,并进行双向数据传输,直到结束,关闭浏览器才会断开连接。
WebSocket的优点:
Ajax轮询
WebSocket相比较Ajax轮询要方便很多,因为WebSocket 并不限于以Ajax(或XHR)方式通信,Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以彼此相互推送信息。并且Ajax轮询是每次访问都要发送请求然后获取服务器的响应来显示数据就如下图:
这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。大多数 Web 应用程序将通过频繁的异步JavaScript和XML(AJAX)请求实现长轮询。轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开),效率很低。而且当访问量大时,服务器的压力是非常大的。
<script>
setInterval("test()",500);
function test() {
$.ajax({
url: '/new_window_url/',
async:true,
type: 'get',
success: function (data) {
var new_url = $('#new_iframe').attr('src');
if (new_url !== data){
$('#new_iframe').attr('src', data);
}
}
})
}
16 </script>
Ajax轮询关键代码
WebSocket
而WebSocket只进行一次连接就不用再连接了,直到WebSocket被关闭才会停止:
WebSocket API的优势在于服务器和客户端可以在固定的时间范围内的任意时刻,相互推送消息。在建立连接之后,服务器可以主动传送数据给客户端。
WebSocket的原理:
浏览器请求:
GET /webfin/websocket/ HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==
Origin: http://服务器地址
Sec-WebSocket-Version: 13
服务器回应:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
WebSocket借用http请求进行握手,相比正常的http请求,多了一些内容。其中,
Upgrade: websocket
Connection: Upgrade
表示希望将http协议升级到Websocket协议。
Sec-WebSocket-Key是浏览器随机生成的base64 encode的值,用来询问服务器是否是支持WebSocket。
服务器返回
Upgrade: websocket
Connection: Upgrade
告诉浏览器即将升级的是Websocket协议
Sec-WebSocket-Accept是将请求包“Sec-WebSocket-Key”的值,与”258EAFA5-E914-47DA-95CA-C5AB0DC85B11″这个字符串进行拼接,然后对拼接后的字符串进行sha-1运算,再进行base64编码得到的。用来说明自己是WebSocket助理服务器。
如何使用WebSocket?
1.首先在maven导入所需要的jar文件:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
2.再创建一个拦截器:
@Configuration
@EnableWebSocket
public class MySocketConfig implements WebSocketConfigurer {
//websocket入口,允许访问的域、注册Handler、SockJs支持和拦截器。
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(),"/websocket")//入口路径为websocket
.addInterceptors(new SpringWebSocketHandler())
.setAllowedOrigins("*");
}
}
3.创建握手拦截器,重写beforeHandshake方法,这个方法负责拦截HttpSess中的数据,放到WebSocket Session 中:
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
System.out.println("Before Handshake");
//在握手之前将HttpSession中的用户,copy放到WebSocket Session中
if (request instanceof ServletServerHttpRequest){
ServletServerHttpRequest servletServerHttpRequest=
(ServletServerHttpRequest) request;
HttpSession session=
servletServerHttpRequest.getServletRequest().getSession(true);
if (null!=session){
User user=(User)session.getAttribute("user");
//WebSocket Session
attributes.put("user",user);
}
}
return super.beforeHandshake(request,response,wsHandler,attributes);
}
这些只是部分重要代码.
如果有不对的地方还请指教!!!
ps:websocket api在浏览器端的广泛实现似乎只是一个时间问题了, 值得注意的是服务器端没有标准的api, 各个实现都有自己的一套api, 并且tcp也没有类似的提案, 所以使用websocket开发服务器端有一定的风险.可能会被锁定在某个平台上或者将来被迫升级。