websocket

2020-02-11  本文已影响0人  鹏程1995

简述

大四狗,正在外边实习,前一段时间部门轮流做技术分享,轮到我了。恰好有一个项目要加功能,大概需求是任务发布者A向另一个人B发布任务。

大概的要求就是这些,第二点很简单,登陆后扫一遍就OK。第一个就有些问题了,在不刷新页面的情况下获得通知,在以前都是后台使用ajax轮询的,对服务器的压力比较大。boss说用WebSocket搞一下。我在9月中旬看了两天的websocket,后来就放下了,这几天又捡了捡。下面将WebSocket和轮询作比较,从为什么用WebSocketWebSocket工作原理,基于Spring MVC的WebSocket搭建三个方面说一下。

正题

为什么用WebSocket

几种解决方案

轮询

轮询分为长轮询和短轮询。

短轮询过程图

1.png

长轮询过程图

2.png

长连接

通俗的来说,长连接的连接是要保持一段时间的,短连接用完就丢。长短连接和上边的长短轮询是不一样的:

长短轮询指的是服务器端是否及时返回浏览器端消息。长短连接指的是建立的TCP连接是否保持。轮询是长还是短主要取决于服务器端的处理策略;连接是长是短取决于浏览器和服务器双方,这个要看通讯协议的。

举个栗子,拿HTTP1.0和HTTP1.1来说吧,在HTTP1.1中新加了一个keep-alive字段。在传统的HTTP1.0通讯协议中,用户发起HTTP请求时会经历一下过程:

  1. 用户和服务器三次握手,建立TCP连接。
  2. 用户发送HTTP请求request
  3. 服务器返回响应response
  4. 用户和服务器四次握手,断开TCP连接。

HTTP1.0时序图


3.png

在HTTP1.1中,有一个keep-alive,默认情况下,采用是长连接,我们不妨假设HTTP1.1的keep-alive设置的时间是m,对应的TCP也有一个keep-alive,设置的时间是n。此时用户发起HTTP请求的过程就变成了下面这样:

  1. 用户和服务器三次握手,建立TCP连接。
  2. 用户发送HTTP请求request。
  3. 服务器返回响应response。
  4. 从此开始计时,m时间内如果没有HTTP请求则四次握手断开TCP连接。如果之前已经有到计时了,则刷新计时为m
  5. 用户有新的HTTP请求,直接跳到第2步。

在2,3,4,5过程中,连接如果长时间没有发送或者接收消息,服务器和浏览器为了确定互相都在线,就在TCP中约定了一个keep-alive字段。上边设置keep-alive为n,也就是说当TCP连接在n时间内没有通讯的话,就用心跳包来保活。

HTTP1.1时序图


4.png

WebSocket工作原理

其实上边已经解释的差不多了,HTTP1.1虽然有keep-alive字段,但是长连接只是保持了TCP不立刻断开,在短时间内多次请求的情况下是TCP连接可以复用。但是HTTP通讯协议服务器只能被动接受,还是不能主动发送消息。

于是在H5规范中就提出来一个新的通讯协议:WebSocket协议。WebSocket是一个基于TCP连接的全双工的通讯协议,在2011年被列入标准。有人把WebSocker当作HTTP协议长连接的“大补丁”。

WebSocket,HTTP,TCP的关系

5.png

图中WebSocket和HTTP之间有一些交互,这是因为WebSocket是通过HTTP协议进行一次握手。握手成功后就可以正常通讯了。

这里还有一个问题,也是学习了WebSocket后大家都经常问你的问题:

WebSocket和Socket的区别是什么?

网络分为七层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。

IP是工作在网络层的,通过IP可以唯一确定网络中的一台主机,TCP/UDP工作在传输层,通过协议和端口号可以唯一确定主机中的一个进程。所以有了TCP/IP协议进行不同主机的进程间的通讯。但是TCP/IP协议很复杂,所有有了socket,把下层的复杂的TCP/IP协议屏蔽掉,向上层提供简单的接口。

WebSocket工作在应用层,是一个完整的通讯协议。

两者没有任何关系。

基于Spring MVC的WebSocket搭建

创建WebSocket处理类

Spring在org.springframework.web.socket包里提供了WebSocketHandeler接口。

并在org.springframework.web.socket.handler包里提供了实现了此接口的可以继承的类:

TextWebSocketHandler                   
    //    ----------文本收发,可用来传信息
BinaryWebSocketHandler           
    //    ----------二进制文件收发,可用作上传下载
AbstractWebSocketHandler        
    //    ----------前两者的父类,实现了WebSocketHandeler接口,并列出了前两者的所有方法

//WebSocketHandeler接口
package org.springframework.web.socket;

public interface WebSocketHandler {
    void afterConnectionEstablished(WebSocketSession var1) throws Exception;

    void handleMessage(WebSocketSession var1, WebSocketMessage<?> var2) throws Exception;

    void handleTransportError(WebSocketSession var1, Throwable var2) throws Exception;

    void afterConnectionClosed(WebSocketSession var1, CloseStatus var2) throws Exception;

    boolean supportsPartialMessages();
}

创建握手接口

Spring在org.springframework.web.socket包里提供了HandshakeInterceptor接口。

并在org.springframework.web.socket.server.support包里提供了实现了此接口的可以继承的类:

<pre>HttpSessionHandshakeInterceptor
// ----------通过http握手时使用,
可以用来查验httpSession中的登陆数据
OriginHandshakeInterceptor
// ----------面向可访问来源的筛选</pre>

下面是HandshakeInterceptor的接口

<pre>public interface HandshakeInterceptor {
boolean beforeHandshake(ServerHttpRequest var1, ServerHttpResponse var2, WebSocketHandler var3, Map<String, Object> var4) throws Exception;
void afterHandshake(ServerHttpRequest var1, ServerHttpResponse var2, WebSocketHandler var3, Exception var4);}</pre>

处理类和握手协议的配置

Spring在org.springframework.web.socket.config.annotation包里提供了WebSocketConfigurer接口。实现这个接口并实现registerWebSocketHandlers(WebSocketHandlerRegistrywebSocketHandlerRegistry)方法,配置websocket入口,允许访问的域、注册Handler、SockJs支持和拦截器。

public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
        webSocketHandlerRegistry
                .addHandler(handler,"/aWebSocket")//添加一个处理器还有定义处理器的处理路径
                .addInterceptors(handlerShakerInceptor)//添加一个过滤器
                .setAllowedOrigins("*");

    }

附录里有完整的项目代码。给整个项目我觉得比在这里粘代码要好得多,就不粘了。

上一篇下一篇

猜你喜欢

热点阅读