WebSocket 协议简介

WebSocket 协议提供了一种标准化的方式,在客户端和服务端建立在一个TCP 连接之上的全双工,双向通信的协议。

WebSocket 交互开始于 HTTP 请求,使用 HTTP 请求的 header 中的 Upgrade 进行切换到 WebSocket 协议。

HTTP 和 WebSocket 对比

即使 WebSocket 的设计兼容 HTTP 协议和开始于 HTTP 请求,了解两个协议是不同架构和应用模型是非常重要的。

在 HTTP 和 REST, 一个应用有多个URL, 对于交互的应用,客户端可以访问这些 URL,请求和响应的风格。服务端会根据 URL、http method、header 等等信息进行路由处理。

相比之下, WebSocket 协议是使用一个URL 初始化连接。应用所有的消息通过同一个 TCP 通信,这一点是完全不同的异步、事件驱动的消息传递体系结构。

WebSocket API 的使用

  1. Webflux 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
  1. 定义一个Handler,用于处理数据的请求和响应
import java.time.Duration;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.WebSocketSession;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; public class MyWebSocketHandler implements WebSocketHandler {
// 每间隔 1 秒,数字加 1
private Flux<Long> intervalFlux = Flux.interval(Duration.ofSeconds(1L), Duration.ofSeconds(1L)); @Override
public Mono<Void> handle(WebSocketSession session) {
return session.send(intervalFlux.map(item -> session.textMessage(item + "")))
.and(session.receive().map(WebSocketMessage::getPayloadAsText).log());
}
}
  1. 配置类,配置 WebSocket 的 URL 信息
@Configuration
public class WebConfig { @Bean
public WebSocketHandlerAdapter handlerAdapter() {
return new WebSocketHandlerAdapter();
} @Bean
public HandlerMapping handlerMapping() {
Map<String, WebSocketHandler> urlMap = new HashMap<>();
urlMap.put("/path", new MyWebSocketHandler());
int order = -1;
return new SimpleUrlHandlerMapping(urlMap, order);
}
}
  1. 客户端
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Duration;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient;
import org.springframework.web.reactive.socket.client.WebSocketClient;
import reactor.core.publisher.Mono; public class Client { public static void main(String[] args) throws URISyntaxException { WebSocketClient client = new ReactorNettyWebSocketClient();
URI url = new URI("ws://localhost:8080/path");
client.execute(url,
session -> session.send(Mono.just(session.textMessage("hello world")))
.thenMany(session.receive().map(WebSocketMessage::getPayloadAsText).log())
.then())
.block(Duration.ofSeconds(10));
}
}

服务端日志

2021-08-10 22:42:36.162  INFO 85792 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port(s): 8080
2021-08-10 22:42:36.168 INFO 85792 --- [ main] c.e.s.SpringBootDemoApplication : Started SpringBootDemoApplication in 3.583 seconds (JVM running for 4.462)
2021-08-10 22:42:51.518 INFO 85792 --- [ctor-http-nio-2] reactor.Flux.Map.1 : onSubscribe(FluxMap.MapSubscriber)
2021-08-10 22:42:51.522 INFO 85792 --- [ctor-http-nio-2] reactor.Flux.Map.1 : request(unbounded)
2021-08-10 22:42:51.534 INFO 85792 --- [ctor-http-nio-2] reactor.Flux.Map.1 : onNext(hello world)
2021-08-10 22:43:00.956 INFO 85792 --- [ctor-http-nio-2] reactor.Flux.Map.1 : onComplete()

客户端日志

22:42:51.527 [reactor-http-nio-1] DEBUG reactor.netty.channel.FluxReceive - [id: 0xd95be56c, L:/127.0.0.1:50773 - R:localhost/127.0.0.1:8080] Subscribing inbound receiver [pending: 0, cancelled:false, inboundDone: false]
22:42:51.530 [reactor-http-nio-1] INFO reactor.Flux.Map.1 - onSubscribe(FluxMap.MapSubscriber)
22:42:51.531 [reactor-http-nio-1] INFO reactor.Flux.Map.1 - request(unbounded)
22:42:52.518 [reactor-http-nio-1] INFO reactor.Flux.Map.1 - onNext(0)
22:42:53.513 [reactor-http-nio-1] INFO reactor.Flux.Map.1 - onNext(1)
22:42:54.518 [reactor-http-nio-1] INFO reactor.Flux.Map.1 - onNext(2)
22:42:55.513 [reactor-http-nio-1] INFO reactor.Flux.Map.1 - onNext(3)
22:42:56.514 [reactor-http-nio-1] INFO reactor.Flux.Map.1 - onNext(4)
22:42:57.516 [reactor-http-nio-1] INFO reactor.Flux.Map.1 - onNext(5)
22:42:58.518 [reactor-http-nio-1] INFO reactor.Flux.Map.1 - onNext(6)
22:42:59.512 [reactor-http-nio-1] INFO reactor.Flux.Map.1 - onNext(7)
22:43:00.513 [reactor-http-nio-1] INFO reactor.Flux.Map.1 - onNext(8)
22:43:00.947 [main] INFO reactor.Flux.Map.1 - cancel()
22:43:00.948 [reactor-http-nio-1] DEBUG reactor.netty.http.client.HttpClientOperations - [id: 0xd95be56c, L:/127.0.0.1:50773 - R:localhost/127.0.0.1:8080] Cancelling Websocket inbound. Closing Websocket
Exception in thread "main" java.lang.IllegalStateException: Timeout on blocking read for 10000 MILLISECONDS

至此,Spring WebFlux 中 WebSocket 协议使用的结束了。

Spring WebFlux 基础教程:WebSocket 使用的更多相关文章

  1. Spring WebFlux 基础教程:参数校验

    请求参数校验,在实际的应用中很常见,网上的文章大部分提供的使用注解的方式做参数校验.本文主要介绍 Spring Webflux Function Endpoint 使用 Spring Validati ...

  2. Spring Boot 基础教程系列学习文档

    Spring Boot基础教程1-Spring Tool Suite工具的安装 Spring Boot基础教程2-RESTfull API简单项目的快速搭建 Spring Boot基础教程3-配置文件 ...

  3. Spring Cloud基础教程

    Spring Cloud基础教程  2017-04-04 被围观 90375 次 该教程内容不定时更新,如您对这些内容感兴趣,可以关注我的博客或微信公众号! 本教程示例代码: GitHub:https ...

  4. Spring Boot基础教程》 第1节工具的安装和使用

    <Spring Boot基础教程> 第1节 工具的安装和使用 Spring Boot文档 https://qbgbook.gitbooks.io/spring-boot-reference ...

  5. 经典Spring入门基础教程详解

    经典Spring入门基础教程详解 https://pan.baidu.com/s/1c016cI#list/path=%2Fsharelink2319398594-201713320584085%2F ...

  6. Spring Cloud基础教程视频教程

    视频课程包含: Spring Cloud基础视频教程24G 目录 获取方式: 关注公众微信号:博涵大数据 或者扫描下面的二维码关注获取. 关注后在公众平台上回复"SpringCloud基础& ...

  7. Spring Cloud Alibaba基础教程:Nacos的集群部署

    继续说说生产环境的Nacos搭建,通过上一篇<Spring Cloud Alibaba基础教程:Nacos的数据持久化>的介绍,我们已经知道Nacos对配置信息的存储原理,在集群搭建的时候 ...

  8. Spring Cloud Alibaba基础教程:Sentinel使用Apollo存储规则

    上一篇我们介绍了如何通过Nacos的配置功能来存储限流规则.Apollo是国内用户非常多的配置中心,所以,今天我们继续说说Spring Cloud Alibaba Sentinel中如何将流控规则存储 ...

  9. Spring Cloud Alibaba基础教程:Sentinel使用Nacos存储规则

    通过上一篇<使用Sentinel实现接口限流>的介绍,相信大家对Sentinel已经有了初步的认识.在Spring Cloud Alibaba的整合封装之下,接口限流这件事情可以非常轻易的 ...

随机推荐

  1. 海量数据Excel报表利器——EasyExcel(开场篇)

    EasyExcel 简介篇 互联网的精髓就是共享,可以共享技术.共享经验.共享情感.共享快乐~ 很多年前就有这个想法了,从事IT行业时间也不短了,应该把自己工作和业余所学习的东西记录并分享出来,和有缘 ...

  2. 美化terminal时碰到的问题- Set-Theme

    报错: 1 Set-Theme Set-Theme: The term 'Set-Theme' is not recognized as a name of a cmdlet, function, s ...

  3. 『动善时』JMeter基础 — 52、使用JMeter测试Dubbo接口

    目录 1.Dubbo介绍 2.准备测试Dubbo接口的环境 3.Dubbo Sample界面详解 4.Dubbo Sample组件的使用 (1)测试计划内包含的元件 (2)使用zookeeper协议请 ...

  4. 11、gitlab和Jenkins整合(1)

    1.在jenkins上安装git: 因为jenkins需要在gitlab上拉取代码: 具体的git安装,参考"4.git和gitlab的配置--4.2.git编译安装:": 2.在 ...

  5. 26、mysqlsla慢查询日志分析工具

    1.介绍: mysqlsla是hackmysql.com推出的一款MySQL的日志分析工具,可以分析mysql的慢查询日志.分析慢查询非常好用,能针 对库分析慢查询语句的执行频率.扫描的数据量.消耗时 ...

  6. 聊一聊我在 B 站自学 Java 的经历吧

    Hey guys ,这里是 cxuan,欢迎你收看我最新一期的文章. 这是一篇鸽了很久的文章...... 事情还要从上回说起...... 我爱 B 站! 这篇文章我汇总了 B 站上计算机基础(操作系统 ...

  7. 使用curl断点续传下载文件

    办公网络网速不是很好,使用Chrome下载一些软件时不时会中断,恶心的是Chrome居然不支持断点续传下载(为什么chrome的下载不支持断点续传呢?),迅雷自然是不能装的,那怎么办?还好我有大名鼎鼎 ...

  8. jenkins send files or publish

    1.创建一个自由风格项目 2.添加用户凭据 3.配置git 4.配置构建方式 这里选择 send files or execute command over SSH 5.配置远程发布脚本 6.构建 7 ...

  9. 『心善渊』Selenium3.0基础 — 24、Selenium的expected_conditions模块详细介绍

    目录 1.EC模块介绍 2.EC模块常用类 3.EC模块的使用 4.EC模块综合使用 (1)title_is(title)示例 (2)presence_of_element_located(locat ...

  10. ARTS第二周

    第二周. 1.Algorithm:每周至少做一个 leetcode 的算法题2.Review:阅读并点评至少一篇英文技术文章3.Tip:学习至少一个技术技巧4.Share:分享一篇有观点和思考的技术文 ...