• spring、tomcat是如何配合完成websocket


    综述

    像IM这一类web系统,需要有机制知道是否有新消息,没有websocket前主要靠轮训。
    轮训频率设得过高,有效轮训率低,不仅消耗网络资源,还占用cpu资源;轮训频率设得过低,又会造成消息延时较大。
    为此诞生了websocket,消息可以由服务端主动推送到客户端,不仅实时性高,效率也是拉满。
    为了尽量减少对现有系统进行改造,websocket是在建立在http的基础之上的,这样不仅可以复用http的端口,服务端及客户端的改造都更小。

    websocket协议

    在这里插入图片描述

    1. 握手阶段:如上所述websocket是基于http,主要是握手阶段仍使用http协议,当HTTP处理器发现头部带“Upgrade: websocket”,则认为连接是要升级到websocket的协议;如果支持websocket则返回允许升级到websocket的响应。
    2. 通信阶段:客户端接受到服务端允许升级协议的响应后,则认为握手完成,后续都以websocket格式发送报文。

    websocke报文格式如下(图片来源https://zhuanlan.zhihu.com/p/407711596):
    在这里插入图片描述

    websocket协议本身很简单,各个字段的含义可以参考其他文章,这里不再详述,本文主要分析tomcat如何实现websocket以及spring boot如何基于tomcat集成websocket。
    本文基于tomcat NIO模式进行分析。
    分析前可以大致梳理一下,有哪些关键点。

    1. tomcat NIO模式下,会为每个请求分配一个线程进行处理,websocket是长连接,这个线程是否会与websocket连接绑定,而一直被同一个websocket占有。
    2. websocket协议升级是在那个点触发的。
    3. tomcat是如何在http的基础之上支持websocket
    4. tomcat的websocket是如何暴露接口给spring去集成的。

    tomcat NIO模式下线程模型

    在这里插入图片描述
    各个线程的初始化详见org.apache.tomcat.util.net.NioEndpoint#startInternal

    1. Acceptor线程主逻辑用于调用accept方法接受请求,生成socket并在Poller中注册
    2. Poller线程主逻辑是调用select方法,获取可读写的socket,并创建SocketProcessor,并丢给Processor线程进行处理。
    3. Processor线程主要逻辑是根据协议解析socket中的数据,并调用servlet容器进行业务处理。

    tomcat NIO模式下请求处理流程

    在这里插入图片描述
    本文不详细解析tomcat的内部实现,http协议本身很简单,没有握手的过程,仅仅只是简单的请求/应答。理论上,只需要 接受请求 -> 解析报文 -> 丢给servlet处理 这几个过程。
    tomcat为了实现更丰富的功能抽象出Engine,Host,Context等概念,为了便于理解我们简化一下tomcat模型,我们将CoyoteAdapter到StandardWrapper当成servlet容器内部的行为,将其合并为Servlet Container,其功能就是将request路由到正确的servlet进行处理。
    那么请求的处理过程可以简化成
    在这里插入图片描述

    1. SocktProcessor主要做协议解析,将socket中的字节流转换成一帧帧HTTP报文
    2. servlet container主要请求路由,跟url信息转发到正确的servlet进行处理
    3. FilterChain这个是servlet规范中的FilterChain,在请求在交给servlet处理前,会经过一系列的Filter进行处理
    4. servlet这个就不解释了。

    websocket协议升级涉及的点

    1. websocket与http有点区别,websocket是长连接(虽然http也可以配置 keepalive在实现长连接,但是服务端并不保证客户端一直没有发请求的情况下仍然保持连接),正常情况下只有双方其中一端显式关闭连接,才能结束这个socket。所以SocktProcessor要了解到该socket连接是有升级过协议的;不仅如此因为websocket是基于http,共用端口,所以SocktProcessor也要感知到socket连接是升级过协议,这样完成握手后的请求,要由websocket的协议处理器去做协议解析。
    2. websocket协议本身并没有鉴权等设计,这个需要委托给握手阶段的http报文的处理。为此握手阶段的报文要当成正常的http协议处理,需要走所有已配置的Filter;所以握手阶段的处理一定会走到servlet容器里面,而且spring应该会注册专门的handler去处理升级前的http报文。
    3. servlet处理模型与websocket不一致,所以框架里面应该会有注册websocket的handler的逻辑。

    待续

  • 相关阅读:
    wireshark远程抓包
    106 基于消息队列来做 mysql 大数据表数据的遍历处理
    js array数组json去重
    Kyligence 联合创始人兼 CEO 韩卿荣获金融科技风云人物奖
    nodejs下载指定版本
    Qt Designer生成ui文件,如何转py文件,如何运行
    C#获取声音信号并通过FFT得到声音频谱
    tensorflow2 -------------LeNet--------------
    影响MySQL索引B+树高度的是什么?
    本地window环境安装mongoDB
  • 原文地址:https://blog.csdn.net/shuxiaohua/article/details/126441978