Java Websocket 02: 原生模式通过 Websocket 传输文件

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

目录

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

Websocket 原生模式 传输文件

关于 Websocket 传输的消息类型, 允许的参数包括以下三类

  1. 以下类型之一, 同时只能出现一个
    • 文本类型 (text messages) 的消息: String, Java primitive, 阻塞的 Stream Reader, 带text decoder(Decoder.Text or Decoder.TextStream)的对象
    • 二进制类型 (binary messages) 的消息: byte[] 或 ByteBuffer, 阻塞的 InputStream, 带 binary decoder (Decoder.Binary or Decoder.BinaryStream)的对象
    • Pong messages: PongMessage
  2. 通过 PathParam 指定的0个或多个基础类型
  3. 会话参数 Session, 可选

因此对于不同的消息类型, 可以有不同参数类型的 onMessage() 方法, 分别用于处理不同格式的内容, 对于传输文件, 需要使用 ByteBuffer 类型的参数

void onMessage(ByteBuffer byteBuffer, Session session)

在处理过程中和普通的文件传输是一样的, 需要将文件分片传输, 并约定合适的消息头用于判断文件传输的阶段, 在服务端根据不同的阶段进行文件创建, 写入和结束.

演示项目

与前一篇项目结构相同, 只需要修改 SocketServer 和 SocketClient

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

SocketServer.java

增加了 onMessage(ByteBuffer byteBuffer, Session session) 方法用于处理二进制消息, 在方法中

  1. 先读取第一个字节的值, 根据不同的值对应不同的操作
    • 1 表示文件传输前的准备
    • 3 表示文件内容写入
    • 5 表示文件结束
  2. 再读取后续的值
    • 1 解析出文件元信息, 并创建文件通道
    • 3 将内容写入文件
    • 5 关闭文件通道, 清除buffer
  3. 回传ACK
    • 1 ACK 2
    • 3 不ACK
    • 5 ACK 6
@Component
@ServerEndpoint("/websocket/server/{sessionId}")
public class SocketServer {

    //...

    @OnMessage
    public void onMessage(ByteBuffer byteBuffer, Session session) throws IOException {
        if (byteBuffer.limit() == 0) {
            return;
        }

        byte mark = byteBuffer.get(0);
        if (mark == 1) {
            log.info("mark 1");
            byteBuffer.get();
            String info = new String(
                    byteBuffer.array(),
                    byteBuffer.position(),
                    byteBuffer.limit() - byteBuffer.position());
            FileInfo fileInfo = new JsonMapper().readValue(info, FileInfo.class);
            byteChannel = Files.newByteChannel(
                    Path.of("D:/data/" + fileInfo.getFileName()),
                    new StandardOpenOption[]{StandardOpenOption.CREATE, StandardOpenOption.WRITE});
            //ack
            ByteBuffer buffer = ByteBuffer.allocate(4096);
            buffer.put((byte) 2);
            buffer.put("receive fileinfo".getBytes(StandardCharsets.UTF_8));
            buffer.flip();
            session.getBasicRemote().sendBinary(buffer);
        } else if (mark == 3) {
            log.info("mark 3");
            byteBuffer.get();
            byteChannel.write(byteBuffer);
        } else if (mark == 5) {
            log.info("mark 5");
            //ack
            ByteBuffer buffer = ByteBuffer.allocate(4096);
            buffer.clear();
            buffer.put((byte) 6);
            buffer.put("receive end".getBytes(StandardCharsets.UTF_8));
            buffer.flip();
            session.getBasicRemote().sendBinary(buffer);
            byteChannel.close();
            byteChannel = null;
        }
    }

    //...

    public static class FileInfo implements Serializable {
        private String fileName;
        private long fileSize;

        public String getFileName() {return fileName;}
        public void setFileName(String fileName) {this.fileName = fileName;}
        public long getFileSize() {return fileSize;}
        public void setFileSize(long fileSize) {this.fileSize = fileSize;}
    }
}

SocketClient.java

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

首先是消息处理中增加了 void onMessage(ByteBuffer bytes), 这个是用来接收服务端回传的ACK的, 根据第一个字节, 判断服务端的处理结果. 这里使用了一个 condition.notify() 用来通知发送线程继续发送

其次是消息发送中, 用输入的1触发文件发送. 文件发送在 void sendFile(WebSocketClient webSocketClient, Object condition) 方法中进行, 通过一个 condition 对象, 在文件开始传输和结束传输时控制线程的暂停和继续. byteBuffer.flip()用于控制 byteBuffer 从状态变为状态, 用于发送. flip is used to flip the ByteBuffer from "reading from I/O" (putting) to "writing to I/O" (getting).

public class SocketClient {

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

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

        Object condition = new Object();

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

            //...

            @Override
            public void onMessage(ByteBuffer bytes) {
                //To overwrite
                byte mark = bytes.get(0);
                if (mark == 2) {
                    synchronized (condition) {
                        condition.notify();
                    }
                    log.info("receive ack for file info");
                } else if (mark == 6){
                    synchronized (condition) {
                        condition.notify();
                    }
                    log.info("receive ack for file end");
                }
            }

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

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

        wsClient.connect();

        log.info("Connecting ...");
        while (!ReadyState.OPEN.equals(wsClient.getReadyState())) {

        }
        log.info("Connected");

        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String line = scanner.next();
            if ("1".equals(line))
                sendFile(wsClient, condition);
            else
                wsClient.send(line);
        }
    }

    public static void sendFile(WebSocketClient webSocketClient, Object condition){
        new Thread(() -> {
            try {
                SeekableByteChannel byteChannel = Files.newByteChannel(
                        Path.of("/home/milton/Backup/linux/apache-tomcat-8.5.58.tar.gz"),
                        new StandardOpenOption[]{StandardOpenOption.READ});

                ByteBuffer byteBuffer = ByteBuffer.allocate(4*1024);

                byteBuffer.put((byte)1);
                String info = "{\"fileName\": \"greproto.tar.gz\", \"fileSize\":"+byteChannel.size()+"}";
                byteBuffer.put(info.getBytes(StandardCharsets.UTF_8));
                byteBuffer.flip();
                webSocketClient.send(byteBuffer);
                synchronized (condition) {
                    condition.wait();
                }

                byteBuffer.clear();
                byteBuffer.put((byte)3);
                while (byteChannel.read(byteBuffer) > 0) {
                    byteBuffer.flip();
                    webSocketClient.send(byteBuffer);
                    byteBuffer.clear();
                    byteBuffer.put((byte)3);
                }

                byteBuffer.clear();
                byteBuffer.put((byte)5);
                byteBuffer.put("end".getBytes(StandardCharsets.UTF_8));
                byteBuffer.flip();
                webSocketClient.send(byteBuffer);
                synchronized (condition) {
                    condition.wait();
                }
                byteChannel.close();

            } catch (InterruptedException|IOException e) {
                log.error(e.getMessage(), e);
            }

        }).start();
    }
}

运行示例

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

将 SocketClient.java 中的文件路径 D:/WorkJava/tmp/greproto.tar.gz 换成自己本地的文件路径, 运行 SocketClient, 可以观察到服务端接收到的消息. 如果输入1并回车, 就会触发客户端往服务端传输文件文章来源地址https://www.toymoban.com/news/detail-489805.html

参考

  • https://stackoverflow.com/questions/14792968/what-is-the-purpose-of-bytebuffers-flip-method-and-why-is-it-called-flip

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

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

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

相关文章

  • 【Nginx笔记02】通过Nginx服务器转发客户端的WebSocket接口到后端服务

    这篇文章,主要介绍如何通过Nginx服务器转发客户端的WebSocket接口到后端服务【知识星球】。 目录 一、Nginx配置WebSocket 1.1、Nginx配置内容 1.2、客户端请求地址 1.3、创建WebSocket测试工程 1.4、启动测试 1.5、WebSocket超时问题 1.5.1、设置超时时间 1.5.2、建立心跳机制(推荐) 今天

    2024年04月11日
    浏览(48)
  • 远程服务和web服务和前端,三方通过socket和websocket进行双向通信传输数据

    1. 什么是socket? 在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。 2. 什么是websocket? WebSocket是一种网络通信协议,是HTML5新增的特性,

    2024年02月15日
    浏览(58)
  • MySQL-02.MySQL的数据目录和表文件解析

    1.1 数据库文件的存放路径 MySQL数据库文件的存放路径 : /var/lib/mysql 从结果中可以看出,在我的计算机上MySQL的数据目录就是 /var/lib/mysql/ 。 1.2 MySQL相关命令目录 相关命令目录:/usr/bin(mysqladmin、mysqlbinlog、mysqldump等命令)和/usr/sbin。 1.3 配置文件目录 配置文件目录:/usr/shar

    2024年03月11日
    浏览(42)
  • 通过xshell传输文件到服务器

    参考链接: [已解决]user is not in the sudoers file. This incident will be reported.(简单不容易出错的方式)-CSDN博客 简单解释下就是: 0、你的root需要设置好密码 像这样,我以一个新用户user1为例: 1、设置好密码之后,就可以切换到root用户: 这里root可以省略,默认就是切换root 像这样

    2024年02月04日
    浏览(63)
  • Android 蓝牙通信(通过 BluetoothSocket 传输文件/文本)

    前言 :Android 蓝牙通信,通过BluetoothSocket方式建立长连接并传输文本或文件。前段时间有个项目的功能需求是:AR眼镜通过蓝牙的方式连接北斗设备,当北斗设备收到文本/语音/图片消息时转发到AR眼镜上,AR眼镜也可以发送文本/语音/图片数据到北斗设备上并转发到指定的目标

    2024年04月14日
    浏览(46)
  • QT-通过tcp传输文件和文本消息

    在建立连接的基础上增加了发送文件的功能,在接收端和发送端定义了一个枚举类型,用于判别发送的是文件还是文本消息 客户端ui 1.获取端口号和ip地址,进行连接,再次点击即可断开连接 2.点击发送消息按钮,获取文本框内容,将消息发送出去,其中type为文本消息类型

    2024年02月03日
    浏览(36)
  • ubuntu之间通过ip使用scp传输文件

    以下是ubuntu之间通过ip使用scp传输文件操作。 确保两设备处于同一局域网下。 开启SSH服务,并查看ssh服务是否启动 有ssd输出,说明服务已经启动: 传输本地文件到接收主机 2.1 在接收主机终端查看接收主机ip 显示如下: 如上图所示,主机ip为:192.168.110.4 2.2 进行文件传输,本

    2024年02月15日
    浏览(47)
  • Shell脚本实现SFTP传输文件,通过密码形式

    cat 读取文件内容 grep server : 查找文件内容中包含server字符的,行内容 awk -F ‘=’ :实现字符串分割,分割字符’‘=’ ${print $2}: 其中$2 表示切割后数组中第几值 base -d :解码base64字符串,转为可识别字符串

    2024年02月12日
    浏览(48)
  • 两台电脑如何通过一根网线实现文件高速传输?

    如何通过一根网线连接两台电脑,并实现文件/数据的互传。 假设需要互传文件的两台电脑分别是A电脑和B电脑,需要将A电脑中的某个文件通过网线传输给B电脑。下面是详细的教程: 第一步,在两台电脑上分别设置其IP地址。 设置A电脑的IP 打开网络和共享中心→更改适配器

    2024年02月05日
    浏览(47)
  • Windows11如何通过附近共享发送文件,附近共享传输文件到电脑

      Windows11如何通过附近共享发送文件 ?2018年,微软推出了名为Nearear Share(附近共享)的新功能。Near share是一种在PC之间传输文件的新方式,类似Airdrop的功能,只需要开启蓝牙和WiFi就能分享照片/影片/文件给另一台电脑,无须传输线、USB或者线上的网络空间分享档案!这也是

    2024年02月05日
    浏览(72)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包