从零搭建开发脚手架 Spring Boot实现WebSocket的多种姿势

WebSocket 是Web 浏览器和服务器之间的双向全双工持久连接。一旦建立了 WebSocket 连接,该连接将保持打开状态,直到客户端或服务器决定关闭此连接。

一个典型的用例可能是当一个应用程序涉及多个用户相互通信时,比如在聊天中。

Http、Websocket、SockJs、Stomp介绍


Http

Http超文本传输协议,Http有1.0、1.1、 2.0几个版本,从Http1.1起,默认都开启了Keep-Alive,保持连接持续性,简单地说,当一个网页打开完成后,客户端和服务器之间用于传输Http数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接,这样就降低了资源的消耗优化性能,但是Keep-Alive也是有时间限制的,还有一个客户端只能主动发起请求才能获取返回数据,并不能主动接收后台推送的数据,Websocket便应运而生。

Websocket

Websocket是 Html5新增加特性之一,目的是浏览器与服务端建立全双工的通信方式,解决 http 请求-响应带来过多的资源消耗,同时对特殊场景应用提供了全新的实现方式,比如聊天、股票交易、游戏等对实时性要求较高的行业领域。

http与websocket都是基于TCP(传输控制协议)的,websocket可以看做是对http协议的一个补充。

SockJs

SockJS是一个JavaScript库,为了应对许多浏览器不支持WebSocket协议的问题,设计了备选SockJs。SockJS 是 WebSocket 技术的一种模拟。SockJS会尽可能对应 WebSocket API,但如果WebSocket 技术不可用的话,会自动降为轮询的方式。SockJS会优先选择WebSocket进行连接,但是当服务器或客户端不支持WebSocket时,会自动在 XHR流、XDR流、iFrame事件源、iFrame HTML文件、XHR轮询、XDR轮询、iFrame XHR轮询、JSONP轮询 这几个方案中择优进行连接。

SockJS客户端首先发送GET /info以从服务器获取基本信息,在那之后,它必须决定使用哪种传输方式。如果可能的话,使用WebSocket,如果不是,在大多数浏览器中,至少有一个HTTP流媒体选项,如果还不是,则使用HTTP(长)轮询。

所有传输请求都具有以下URL结构:

http://host:port/myApp/myEndpoint/{server-id}/{session-id}/{transport}

  • {server-id}用于在集群中路由请求,但不用于其他用途。

  • {session-id}关联属于SockJS会话的HTTP请求。

  • {transport}指示传输类型(例如websocketxhr-streaming和其他)。

Github地址:https://github.com/sockjs

Stomp

STOMP是面向流文本的消息传输协议Streaming Text Oriented Messaging Protocol,是 WebSocket 通信标准的一部分,属于业务层的控制协议Wire protocol协议规范。在通常的发布订阅语义之上,它通过 begincommitrollback 事物序列以及ack确认机制来提供消息可靠的投递。由于协议简单且易于实现,几乎所有的编程语言都有 STOMP 的客户端实现。

STOMP协议,来为浏览器 和 server 间的 通信增加适当的消息语义。

STOMP在WebSocket之上提供了一个基于帧的线路格式层,用来定义消息的语义。

传输协议方面,同时支持STOMP Over WebSocketSTOMP Over SockJS

STOMP帧由命令、一个或多个头信息以及负载所组成。例如如下就是发送数据的一个STOMP帧:

SEND

destination:/app/marco

content-length:20

{“message”:“Maeco!”}

WebSocket、SockJs、STOMP三者关系

简而言之,WebSocket 是底层协议,SockJS 是WebSocket 的备选方案,也是底层协议,而 STOMP 是基于 WebSocket(SockJS)的上层协议。

1、HTTP协议解决了 web 浏览器发起请求以及 web 服务器响应请求的细节,假设 HTTP 协议 并不存在,只能使用 TCP 套接字来 编写 web 应用。

2、直接使用 WebSocket(SockJS) 就很类似于 使用 TCP 套接字来编写 web 应用,因为没有高层协议,就需要我们定义应用间所发送消息的语义,还需要确保连接的两端都能遵循这些语义;

3、同HTTP在TCP 套接字上添加请求-响应模型层一样,STOMP在WebSocket 之上提供了一个基于帧的线路格式层,用来定义消息语义;

Websocket多种实现方式


maven依赖先引入

org.springframework.boot

spring-boot-starter-websocket

简单Websocket

与Spring无关,基于tomcat实现

WebSocket 规范支持两种在线数据格式——文本和二进制。API 支持这两种格式,添加了处理规范中定义的 Java 对象和健康检查消息(ping-pong)的功能:

  • Text:任何文本数据(java.lang.String、原语或它们等效的包装类)

  • Binary:由java.nio.ByteBuffer或byte[](字节数组)表示的二进制数据(例如音频、图像等)

  • Java 对象:API 可以在您的代码中使用本机(Java 对象)表示,并使用自定义转换器(编码器/解码器)将它们转换为 WebSocket 协议允许的兼容在线格式(文本、二进制)

  • Ping-Pong:javax.websocket.PongMessage是 WebSocket 对等方响应健康检查 (ping) 请求而发送的确认

服务端

相关注解如下:

  • @ServerEndpoint:如果用@ServerEndpoint 修饰,容器确保类作为WebSocket服务器的可用性,监听特定的 URI 空间

  • @ClientEndpoint:使用此注解修饰的类被视为WebSocket客户端

  • @OnOpen:当启动新的WebSocket连接时,容器会调用带有@OnOpen的 Java 方法

  • @OnMessage:一个Java方法,用@OnMessage注解,当消息发送到端点时从WebSocket容器接收信息

  • @OnError:当通信出现问题时调用带有@OnError的方法

  • @OnClose:用于装饰一个 Java 方法,该方法在WebSocket连接关闭时由容器调用

我们通过使用@ServerEndpoint注解来声明一个 Java 类_WebSocket_服务器端点。我们还指定部署端点的 URI。URI 是相对于服务器容器的根定义的,并且必须以正斜杠开头:

第一步:注入ServerEndpointExporter,这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint。

@Configuration

public class WebSocketEndpointConfig {

@Bean

public ServerEndpointExporter serverEndpointExporter() {

return new ServerEndpointExporter();

}

}

第二步:websocket处理类,注意加@Component

@ServerEndpoint(value = “/chat/{username}”)

@Component

public class ChatEndpoint {

private Session session;

private static Set chatEndpoints = new CopyOnWriteArraySet<>();

private static HashMap<String, String> users = new HashMap<>();

@OnOpen

public void onOpen(

Session session,

@PathParam(“username”) String username) throws IOException {

this.session = session;

chatEndpoints.add(this);

users.put(session.getId(), username);

String message = username + “Connected!”;

broadcast(message);

}

@OnMessage

public void onMessage(Session session, String message)

throws IOException {

broadcast(message);

}

@OnClose

public void onClose(Session session) throws IOException {

chatEndpoints.remove(this);

broadcast(users.get(session.getId()) + “Disconnected!”);

}

@OnError

public void onError(Session session, Throwable throwable) {

// Do error handling here

}

private static void broadcast(String message) {

chatEndpoints.forEach(endpoint -> {

synchronized (endpoint) {

try {

endpoint.session.getBasicRemote().sendText(message);

} catch (IOException e) {

e.printStackTrace();

}

}

});

}

}

客户端

Spring WebSocket

服务端

处理类

public class ChatHandler extends AbstractWebSocketHandler {

@Override

protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

System.out.println("Received message: " + message.getPayload());

Thread.sleep(2000);

session.sendMessage(new TextMessage(“Polo!”));

}

@Override

public void afterConnectionEstablished(WebSocketSession session) {

System.out.println(“Connection established!”);

}

@Override

public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {

System.out.println("Connection closed. Status: " + status);

}

}

配置注册

@Configuration

@EnableWebSocket

public class WebSocketConfig implements WebSocketConfigurer {

@Override

public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

registry.addHandler(chatHandler(), “/chat”).setAllowedOrigins(“*”);

}

@Bean

public ChatHandler chatHandler() {

return new ChatHandler();

}

}

客户端

SockJS

服务端

在上面代码WebSocketConfig.java上重点开启SockJS支持.withSockJS();

@Override

public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

registry.addHandler(chatHandler(), “/chat”).withSockJS();

}

客户端

var url = ‘http://localhost:8080/chat’; //SockJS所处理的URL是http://或https://,不再是ws://和wss://

var sock = new SockJS(url);

//var sock = new WebSocket(url); //打开WebSocket

运行效果一样,但是客户端–服务器之间通信的方式却有了很大的变化。

Stomp

服务端

配置注册

@Configuration

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-J7eHkNQS-1715822124565)]

[外链图片转存中…(img-VN9SJBYR-1715822124565)]

[外链图片转存中…(img-tOauMTxB-1715822124565)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值