Java Websocket 01: 原生模式 Websocket 基础通信

这篇具有很好参考价值的文章主要介绍了Java Websocket 01: 原生模式 Websocket 基础通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

  • Java Websocket 01: 原生模式 Websocket 基础通信
  • Java Websocket 02: 原生模式通过 Websocket 传输文件

Websocket 原生模式

原生模式下

  • 服务端通过 @ServerEndpoint 实现其对应的 @OnOpen, @OnClose, @OnMessage, @OnError 方法
  • 客户端创建 WebSocketClient 实现对应的 onOpen(), onClose(), onMessage(), onError()

演示项目

完整示例代码 https://github.com/MiltonLai/websocket-demos/tree/main/ws-demo01

目录结构

│   pom.xml
└───src
    ├───main
    │   ├───java
    │   │   └───com
    │   │       └───rockbb
    │   │           └───test
    │   │               └───wsdemo
    │   │                       SocketServer.java
    │   │                       WebSocketConfig.java
    │   │                       WsDemo01App.java
    │   └───resources
    │           application.yml
    └───test
        └───java
            └───com
                └───rockbb
                    └───test
                        └───wsdemo
                                SocketClient.java

pom.xml

  • 可以用 JDK11, 也可以用 JDK17
  • 通过 Spring Boot plugin repackage, 生成 fat jar
  • 用 Java-WebSocket 作为 client 的 websocket 实现库, 当前最新版本为 1.5.3
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.rockbb.test</groupId>
    <artifactId>ws-demo01</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>

    <name>WS: Demo 01</name>

    <properties>
        <!-- Global encoding -->
        <project.jdk.version>17</project.jdk.version>
        <project.source.encoding>UTF-8</project.source.encoding>
        <!-- Global dependency versions -->
        <spring-boot.version>2.7.11</spring-boot.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- Spring Boot Dependencies -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-messaging</artifactId>
        </dependency>

        <dependency>
            <groupId>org.java-websocket</groupId>
            <artifactId>Java-WebSocket</artifactId>
            <version>1.5.3</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>ws-demo01</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.10.1</version>
                <configuration>
                    <source>${project.jdk.version}</source>
                    <target>${project.jdk.version}</target>
                    <encoding>${project.source.encoding}</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <encoding>${project.source.encoding}</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

application.yml

设置服务端口为 8763

server:
  port: 8763
  tomcat:
    uri-encoding: UTF-8

spring:
  application:
    name: ws-demo01

WsDemo01App.java

  • 将 @RestController 也合并到应用入口了. 和单独拆开做一个 Controller 类是一样的
  • '/msg' 路径用于从 server 往 client 发送消息
@RestController
@SpringBootApplication
public class WsDemo01App {

    public static void main(String[] args) {
        SpringApplication.run(WsDemo01App.class, args);
    }

    @RequestMapping("/msg")
    public String sendMsg(String sessionId, String msg) throws IOException {
        Session session = SocketServer.getSession(sessionId);
        SocketServer.sendMessage(session, msg);
        return "send " + sessionId + " : " + msg;
    }
}

WebSocketConfig.java

必须显式声明 ServerEndpointExporter 这个 Bean 才能提供 websocket 服务

@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter initServerEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

SocketServer.java

提供 websocket 服务的关键类. @ServerEndpoint 的作用类似于 RestController, 这里指定 client 访问的路径格式为 ws://host:port/websocket/server/[id],
当 client 访问使用不同的 id 时, 会对应产生不同的 SocketServer 实例

@Component
@ServerEndpoint("/websocket/server/{sessionId}")
public class SocketServer {
    private static final org.slf4j.Logger log = LoggerFactory.getLogger(SocketServer.class);
    private static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();

    private String sessionId = "";

    @OnOpen
    public void onOpen(Session session, @PathParam("sessionId") String sessionId) {
        this.sessionId = sessionId;
        /* Old connection will be kicked by new connection */
        sessionMap.put(sessionId, session);
        /*
         * this: instance id. New instances will be created for each sessionId
         * sessionId: assigned from path variable
         * session.getId(): the actual session id (start from 0)
         */
        log.info("On open: this{} sessionId {}, actual {}", this, sessionId, session.getId());
    }

    @OnClose
    public void onClose() {
        sessionMap.remove(sessionId);
        log.info("On close: sessionId {}", sessionId);
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("On message: sessionId {}, {}", session.getId(), message);
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("On error: sessionId {}, {}", session.getId(), error.getMessage());
    }

    public static void sendMessage(Session session, String message) throws IOException {
        session.getBasicRemote().sendText(message);
    }

    public static Session getSession(String sessionId){
        return sessionMap.get(sessionId);
    }
}

关于会话对象 Session

OnOpen 会注入一个 Session 参数, 这个是实际的 Websocket Session, 其 ID 是全局唯一的, 可以唯一确定一个客户端连接. 在当前版本的实现中, 这是一个从0开始自增的整数. 如果你需要实现例如单个用户登录多个会话, 在通信中, 将消息转发给同一个用户的多个会话, 就要小心记录这些 Session 的 ID.

@OnOpen
public void onOpen(Session session, @PathParam("sessionId") String sessionId)

关于会话意外关闭

在客户端意外停止后, 服务端会收到 OnError 消息, 可以通过这个消息管理已经关闭的会话

SocketClient.java

client 测试类, 连接后可以通过命令行向 server 发送消息

public class SocketClient {

    private static final org.slf4j.Logger log = LoggerFactory.getLogger(SocketClient.class);

    public static void main(String[] args) throws URISyntaxException {

        WebSocketClient wsClient = new WebSocketClient(
                new URI("ws://127.0.0.1:8763/websocket/server/10001")) {

            @Override
            public void onOpen(ServerHandshake serverHandshake) {
                log.info("On open: {}, {}", serverHandshake.getHttpStatus(), serverHandshake.getHttpStatusMessage());
            }

            @Override
            public void onMessage(String s) {
                log.info("On message: {}", s);
            }

            @Override
            public void onClose(int i, String s, boolean b) {
                log.info("On close: {}, {}, {}", i, s, b);
            }

            @Override
            public void onError(Exception e) {
                log.info("On error: {}", e.getMessage());
            }
        };

        wsClient.connect();
        log.info("Connecting...");
        while (!ReadyState.OPEN.equals(wsClient.getReadyState())) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
        }
        log.info("Connected");

        wsClient.send("hello");

        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String line = scanner.next();
            wsClient.send(line);
        }
        wsClient.close();
    }
}

代码的执行过程就是新建一个 WebSocketClient 并实现其处理消息的接口方法, 使用 10001 作为 sessionId 进行连接, 在连接成功后, 不断读取键盘输入 (System.in), 将输入的字符串发送给服务端.

运行示例

示例是一个普通的 Spring Boot jar项目, 可以通过mvn clean package进行编译, 再通过java -jar ws-demo01.jar运行, 启动后工作在8763端口

然后运行 SocketClient.java, 可以观察到服务端接收到的消息.

服务端可以通过浏览器访问 http://127.0.0.1:8763/msg?sessionId=10001&msg=123 向客户端发送消息.

结论

以上说明并演示了原生的 Websocket 实现方式, 可以尝试运行多个 SocketClient, 使用相同或不同的 server sessionId 路径, 观察通信的变化情况.文章来源地址https://www.toymoban.com/news/detail-488981.html

到了这里,关于Java Websocket 01: 原生模式 Websocket 基础通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 聊聊分布式架构01——http通信基础

    目录 web通信的简单结构 网络通信基础TCP/IP TCP/IP 通信传输流 HTTP中的三剑客 负责传输的IP协议 确保可靠性的TCP协议 SYN攻击(SYN Flood Attack) 四次挥手 负责域名解析的DNS服务 基于 TCP 协议实现通信 TCP 协议的通信过程 Web通信的简单结构 Web 使用一种名为 HTTP(HyperText Transfer Pr

    2024年02月07日
    浏览(42)
  • Android程序中使用websocket通信(java-websocket)

    使用场景: 需要和硬件保持实时通信 为什么用websocket: 在以前的消息推送机制中,用的都是http轮询(polling),做一个定时器定时向服务器发送请求,这种方式是非常消耗资源的,因为它本质还是http请求,而且显得非常笨拙。而WebSocket 在浏览器和服务器完成一个握手的动作

    2024年01月23日
    浏览(50)
  • SpringBoot(java)实现websocket实现实时通信

    WebSockets是一种在Web应用程序中实现实时通信的技术。它允许客户端和服务器之间建立持久的、双向的通信通道,从而使得服务器可以实时向客户端推送数据,而不需要客户端不断地向服务器发起请求。这种实时通信的能力对于需要即时更新数据的应用程序非常有用,比如在线

    2024年04月29日
    浏览(53)
  • java中使用sockjs、stomp完成websocket通信

    主要配置 握手拦截(这套方案好像前端无法补充Header,就不在这里做权限校验)这里采用的方法是直接问号拼接token,前端 new SockJS(这里带问号),sockjs使用的是http所以没毛病,本文使用的是OAuth2权限校验 之后可以设置握手之后的身份注入(配置了这个可以在单对单订阅时直接使用) 储

    2024年02月10日
    浏览(36)
  • 【001_IoT/物联网通信协议基础: HTTP、Websocket、MQTT、AMQP、COAP、LWM2M一文搞懂】

    学历代表过去、能力代表现在、学习力代表将来。 一个良好的学习方法是通过输出来倒逼自己输入。写博客既是对过去零散知识点的总结和复盘,也是参加了 零声教育 写博客活动。 零声教育体验课:https://xxetb.xetslk.com/s/3fbO81 本文是开发过程中的知识点总结,供大家学习交

    2024年04月22日
    浏览(39)
  • Java基础01:HelloWorld

    1.安装jdk,并配置环境变量。查看是否成功安装jdk:WIN+R,输入cmd 。进入后输入:java -version 能显示其版本,则安装成功。jdk简化版安装 2.安装IDEA。方便后面的学习使用。 安装过程参考 idea基本设置 3.jdk(开发者工具)、jre(运行时环境)、jvm(虚拟机)三者关系 1.HelloWorld 创建一个文

    2024年02月07日
    浏览(37)
  • Day01-Java基础语法

    目录 1. 人机交互 1.1 什么是cmd? 1.2 如何打开CMD窗口? 1.3 常用CMD命令 1.4 CMD练习 1.5 环境变量 2. Java概述 1.1 Java是什么? 1.2下载和安装 1.2.1 下载 1.2.2 安装 1.2.3 JDK的安装目录介绍 1.3 HelloWorld小案例 2.3.1 Java程序开发运行流程 2.3.2 HelloWorld案例的编写 1.4 HelloWorld案例常见问题 1.

    2024年02月10日
    浏览(39)
  • 【后端开发】01-Java基础语法

    Java基础语法 目录 1. 概述 1.1. 语言特性 1.2. 开发平台 1.3. 开发环境 1.4. 开发步骤 1.5. 注释 2. 变量与运算符 2.1. /保留字 2.2. 标识符 2.3. 变量 2.4. 常用数据类型 2.4.1. 基本数据类型(8种) 2.4.2. 引用数据类型 2.4.3. 数据类型转换 2.5. 运算符 2.5.1. 算术运算符(7个) 2.5.2. 关

    2024年02月08日
    浏览(36)
  • JAVA学习笔记_基础篇01

    https://www.bilibili.com/video/BV1fh411y7R8?p=266spm_id_from=pageDrivervd_source=5c60787a1cdddc0e6d23d53b2b6bb1c4 第一阶段:建立编程思想(包括:基本语法、数组、排序和查找、面向对象编程、零钱通、房屋出租系统、迷宫、八皇后、汉诺塔 ) 第二阶段:提升编程能力(包括: 枚举和注解、Exception、常用类、

    2024年02月08日
    浏览(44)
  • JAVA面试-语法基础- A01

    面向对象特性 利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分隔的独立实体,数据被保护在抽象数据类型的内部,尽可能的隐藏内部的细节,只保留一些对外的接口,用户无需对对象的内部了解过多,但是可以通过对象提供的接口来访问对象。

    2024年02月05日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包