WebSocket简单介绍

一、定义

WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。使web更具交互性的,包括Java applet、XMLHttpRequest、Adobe Flash、ActiveXObject、各种Comet技术、服务器发送的事件等等。

二、产生的原因

传统双工通信

客户端和服务器之间通过多个HTTP连接来实现,造成HTTP轮询的滥用,客户端向服务器不断发送HTTP请求来进行询问,导致效率低下。

  • 服务器被迫为每个客户端使用许多不同的底层TCP连接:一个用于向客户端发送信息,其它用于接收每个传入消息。
  • 有线协议有很高的开销,每一个客户端和服务器之间都有HTTP头。
  • 客户端脚本被迫维护从传出连接到传入连接的映射来追踪回复。

WebSocket协议

结合WebSocket API ,WebSocket协议提供了一个用来替代HTTP轮询实现网页到远程主机的双向通信的方法:使用单个TCP连接双向通信,允许服务器主动发送信息给客户端。

三、实现原理

在实现websocket连线过程中,需要通过浏览器发出websocket连线请求,然后服务器发出回应,这个过程通常称为“握手” 。在 WebSocket API,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

四、限制

一些浏览器中缺少对WebSocket的支持。第一个支持WebSocket的ie是ie10。此外,一些限制性代理可能会以某种方式配置,要么阻止尝试进行HTTP升级,要么在一段时间后断开连接,因为它已经打开了太长时间。

因此,回退选项是必要的,而Spring框架提供了基于SockJS协议的透明的回退选项。

五、消息架构

REST是一种广泛接受、理解和支持的用于构建web应用程序的体系结构。它是一种体系结构,它依赖于拥有许多url(名词)、少数HTTP方法(动词)和其他原则,如使用超媒体(链接)、保持无状态等等。

相比之下,WebSocket应用程序可能只使用一个URL作为初始HTTP握手。之后所有的消息都在相同的TCP连接上共享和流动。这指向一个完全不同的、异步的、事件驱动的消息体系结构。与传统消息应用程序(如JMS、AMQP)更接近的一种。

Spring Framework 4包含一个新的Spring消息模块,其中包含来自Spring Integration项目的关键抽象,比如消息、MessageChannel、MessageHandler,以及其他可以作为消息传递体系结构的基础。该模块还包括一组用于将消息映射到方法的注释,类似于Spring MVC基于注释的编程模型。

六、WebSocket应用场景

WebSocket最适合的是在web应用程序中,客户端和服务器需要频繁地交换事件和低延迟。主要候选者包括但不限于在金融、游戏、合作等方面的应用。这样的应用程序对时间延迟非常敏感,并且需要在高频率的情况下交换各种各样的消息。

它是低延迟和高频率的消息的组合,可以使WebSocket协议的使用成为关键。即使在这样的应用程序中,仍然可以选择是否所有的客户机-服务器通信都应该通过WebSocket消息来完成,而不是使用HTTP和REST。答案会因应用而异;然而,很可能某些功能可能会在WebSocket和REST API中暴露出来,从而为客户提供其他的选择。此外,REST API调用可能需要向通过WebSocket连接的感兴趣的客户端广播消息。

Spring框架允许@Controller和@RestController类同时拥有HTTP请求处理和WebSocket消息处理方法。此外,Spring MVC请求处理方法或任何应用程序方法,都可以轻松地向所有感兴趣的WebSocket客户端或特定的用户广播一条消息。

七、WebSocket API

特点

  • WebSocket API是下一代客户端-服务器的异步通信方法。
  • 该通信取代了单个的TCP套接字,使用ws或wss协议,可用于任意的客户端和服务器程序。
  • 服务器和客户端可以在给定的时间范围内的任意时刻,相互推送信息。(WebSocket并不限于以Ajax(或XHR)方式通信,因为Ajax技术需要客户端发起请求)
  • XHR受到域的限制,而WebSocket允许跨域通信。

用法

以Spring Boot为例:
* 只专注于客户端的API,因为每个服务器端语言有自己的API。

  • pom配置
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-websocketartifactId>
dependency>

有两种写法

a.创建一个TextWebSocketHandler或BinaryWebSocketHandler的派生类
  • 创建和配置一个WebSocketHandler

    1.创建一个WebSocket服务器和实现WebSocketHandler一样简单(继承TextWebSocketHandler或BinaryWebSocketHandler)。

    import org.springframework.web.socket.WebSocketHandler;
    import org.springframework.web.socket.WebSocketSession;
    import org.springframework.web.socket.TextMessage;
    
    public class MyHandler extends TextWebSocketHandler {
    
      @Override
      public void handleTextMessage(WebSocketSession session, TextMessage message) {
          // ...
      }
    
    }

    2.有专门的WebSocket Java-config或XML命名空间支持将上面的WebSocket处理程序映射到一个特定的URL。

    import org.springframework.web.socket.config.annotation.EnableWebSocket;
    import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
    import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
    
    @Configuration
    @EnableWebSocket
    public class WebSocketConfig implements WebSocketConfigurer {
    
      @Override
      public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
          registry.addHandler(myHandler(), "/myHandler");
      }
    
      @Bean
      public WebSocketHandler myHandler() {
          return new MyHandler();
      }
    
    }

    与之等价的XML配置:

    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:websocket="http://www.springframework.org/schema/websocket"
      xsi:schemaLocation="
          http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/websocket
          http://www.springframework.org/schema/websocket/spring-websocket.xsd">
    
      <websocket:handlers>
          <websocket:mapping path="/myHandler" handler="myHandler"/>
      websocket:handlers>
    
      <bean id="myHandler" class="org.springframework.samples.MyHandler"/>
    
    beans>
  • 定制WebSocket握手

    定制初始HTTP WebSocket握手请求的最简单方法是通过一个handshake截取程序,它公开了“前”和“后”握手方法。这样的拦截器可用于阻止握手或对WebSocketSession提供任何属性。例如,有一个内置的拦截器用于将HTTP会话属性传递给WebSocket会话:

    @Configuration
    @EnableWebSocket
    public class WebSocketConfig implements WebSocketConfigurer {
    
      @Override
      public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
          registry.addHandler(new MyHandler(), "/myHandler")
              .addInterceptors(new HttpSessionHandshakeInterceptor());
      }
    
    }

    与之等价的XML配置:

    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:websocket="http://www.springframework.org/schema/websocket"
      xsi:schemaLocation="
          http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/websocket
          http://www.springframework.org/schema/websocket/spring-websocket.xsd">
    
      <websocket:handlers>
          <websocket:mapping path="/myHandler" handler="myHandler"/>
          <websocket:handshake-interceptors>
              <bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/>
          websocket:handshake-interceptors>
      websocket:handlers>
    
      <bean id="myHandler" class="org.springframework.samples.MyHandler"/>
    
    beans>  
  • 配置WebSocket引擎

    1.每个底层WebSocket引擎都暴露了控制运行时特征的配置属性,比如消息缓冲区大小、闲置超时等。

    @Configuration
    @EnableWebSocket
    public class WebSocketConfig implements WebSocketConfigurer {
    
      @Bean
      public ServletServerContainerFactoryBean createWebSocketContainer() {
          ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
          container.setMaxTextMessageBufferSize(8192);
          container.setMaxBinaryMessageBufferSize(8192);
          return container;
      }
    
    }

    与之等价的XML配置:

    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:websocket="http://www.springframework.org/schema/websocket"
      xsi:schemaLocation="
          http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/websocket
          http://www.springframework.org/schema/websocket/spring-websocket.xsd">
    
      <bean class="org.springframework...ServletServerContainerFactoryBean">
          <property name="maxTextMessageBufferSize" value="8192"/>
          <property name="maxBinaryMessageBufferSize" value="8192"/>
      bean>
    
    beans>  

    2.对于Jetty,您需要提供预配置的Jetty WebSocketServerFactory,并通过WebSocket Java配置将其插入到Spring的DefaultHandshakeHandler中。

    @Configuration
    @EnableWebSocket
    public class WebSocketConfig implements WebSocketConfigurer {
    
      @Override
      public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
          registry.addHandler(echoWebSocketHandler(),
              "/echo").setHandshakeHandler(handshakeHandler());
      }
    
      @Bean
      public DefaultHandshakeHandler handshakeHandler() {
    
          WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
          policy.setInputBufferSize(8192);
          policy.setIdleTimeout(600000);
    
          return new DefaultHandshakeHandler(
                  new JettyRequestUpgradeStrategy(new WebSocketServerFactory(policy)));
      }
    
    }

    与之等价的XML配置:

    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:websocket="http://www.springframework.org/schema/websocket"
      xsi:schemaLocation="
          http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/websocket
          http://www.springframework.org/schema/websocket/spring-websocket.xsd">
    
      <bean class="org.springframework...ServletServerContainerFactoryBean">
          <property name="maxTextMessageBufferSize" value="8192"/>
          <property name="maxBinaryMessageBufferSize" value="8192"/>
      bean>
    
    beans>  
  • 打开一个连接,为连接创建事件监听器,断开连接,消息时间,发送消息返回到服务器,关闭连接。

    // 创建一个Socket实例
    var socket = new WebSocket('ws://localhost:8080');
    
    // 打开Socket
    socket.onopen = function(event) {
    
    // 发送一个初始化消息
    socket.send('I am the client and I\'m listening!');
    
    // 监听消息
    socket.onmessage = function(event) {
      console.log('Client received a message',event);
    };
    
    // 监听Socket的关闭
    socket.onclose = function(event) {
      console.log('Client notified socket has closed',event);
    };
    
    // 关闭Socket....
    //socket.close()
    };

项目链接a

b.使用@ServerEndpoint注解

使用@OnOpen,@OnClose,@OnMessage,@OnError等注解,编写相应的函数处理js的相关请求。

项目链接b

你可能感兴趣的:(计算机网络)