前言

上一章实现了websocket传输文本信息,实际上网络传输的都是二进制0和1,因而也可以传输文件。

demo

实现websocket传输文件,使用上次的示例,client

package com.feng.socket.client;import org.java_websocket.client.WebSocketClient;
import org.java_websocket.enums.ReadyState;
import org.java_websocket.handshake.ServerHandshake;import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Scanner;public class SocketClient {public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {Object condition = new Object();WebSocketClient webSocketClient = new WebSocketClient(new URI("ws://127.0.0.1:8083/websocket/server/10001")) {@Overridepublic void onOpen(ServerHandshake serverHandshake) {System.out.println(serverHandshake.getHttpStatus() + " : " + serverHandshake.getHttpStatusMessage());}@Overridepublic void onMessage(String s) {System.out.println("receive msg is " + s);}@Overridepublic void onMessage(ByteBuffer bytes) {//To overwritebyte mark = bytes.get(0);if (mark == 2) {synchronized (condition) {condition.notify();}System.out.println("receive ack for file info");} else if (mark == 6){synchronized (condition) {condition.notify();}System.out.println("receive ack for file end");}}@Overridepublic void onClose(int i, String s, boolean b) {System.out.println(s);}@Overridepublic void onError(Exception e) {e.printStackTrace();}};webSocketClient.connect();while (!ReadyState.OPEN.equals(webSocketClient.getReadyState())) {System.out.println("wait for connecting ...");}//        webSocketClient.send("hello");
//        Scanner scanner = new Scanner(System.in);
//        while (scanner.hasNext()) {
//            String line = scanner.next();
//            webSocketClient.send(line);
//        }System.out.println("start websocket client...");Scanner scanner = new Scanner(System.in);while (scanner.hasNext()) {if ("1".equals(scanner.next()))sendFile(webSocketClient, condition);}}public static void sendFile(WebSocketClient webSocketClient, Object condition){new Thread(() -> {try {SeekableByteChannel byteChannel = Files.newByteChannel(Path.of("/Users/huahua/IdeaProjects/websocket-demo/websocket-demo/socket-client/src/main/resources/Thunder5.rar"),new StandardOpenOption[]{StandardOpenOption.READ});ByteBuffer byteBuffer = ByteBuffer.allocate(4*1024);byteBuffer.put((byte)1);String info = "{\"fileName\": \"Thunder5.rar\", \"fileSize\":"+byteChannel.size()+"}";byteBuffer.put(info.getBytes(StandardCharsets.UTF_8));byteBuffer.flip();webSocketClient.send(byteBuffer);byteBuffer.clear();synchronized (condition) {condition.wait();}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 (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}).start();}
}

Server端使用Tomcat的websocket

package com.feng.socket.admin;import com.fasterxml.jackson.databind.json.JsonMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Component
@ServerEndpoint("/websocket/server/{sessionId}")
public class SocketServer {private static final Logger LOGGER = LoggerFactory.getLogger(SocketServer.class);private static Map<String, Session> sessionMap = new ConcurrentHashMap<>();private String sessionId = "";private SeekableByteChannel byteChannel;@OnOpenpublic void onOpen(Session session, @PathParam("sessionId") String sessionId) {this.sessionId = sessionId;sessionMap.put(sessionId, session);LOGGER.info("new connect, sessionId is " + sessionId);}@OnClosepublic void onClose() {sessionMap.remove(sessionId);LOGGER.info("close socket, the sessionId is " + sessionId);}@OnMessagepublic void onMessage(String message, Session session) {LOGGER.info("--------- receive message: " + message);}@OnMessagepublic void onMessage(ByteBuffer byteBuffer, Session session) throws IOException {if (byteBuffer.limit() == 0) {return;}byte mark = byteBuffer.get(0);if (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("/Users/huahua/"+fileInfo.getFileName()),new StandardOpenOption[]{StandardOpenOption.CREATE, StandardOpenOption.WRITE});//ackByteBuffer 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) {byteBuffer.get();byteChannel.write(byteBuffer);} else if (mark == 5) {//ackByteBuffer 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;}}@OnErrorpublic void onError(Session session, Throwable error) {LOGGER.error(error.getMessage(), error);}public static void sendMessage(Session session, String message) throws IOException {session.getBasicRemote().sendText(message);}public static Session getSession(String sessionId){return sessionMap.get(sessionId);}
}

实现思路

经验分享

实际在使用过程中有2个问题

1. Tomcat的websocket默认最大只能发送8K的数据

根本原因是

org.apache.tomcat.websocket.WsSession

    // Buffersstatic final int DEFAULT_BUFFER_SIZE = Integer.getInteger("org.apache.tomcat.websocket.DEFAULT_BUFFER_SIZE", 8 * 1024).intValue();private volatile int maxBinaryMessageBufferSize = Constants.DEFAULT_BUFFER_SIZE;private volatile int maxTextMessageBufferSize = Constants.DEFAULT_BUFFER_SIZE;

通过系统变量,或者JVM -D参数可设置

org.apache.tomcat.websocket.DEFAULT_BUFFER_SIZE

2. json格式化问题,如果对象的属性有byte[]数组

fastjson和Jackson是使用Base64的方式处理的gson是真byte[]数组存储,只是字符串是包括的。

总结

实际上websocket是tcp上的双工协议,传输文件是没有问题的,只是需要定义应用层协议才行。如果使用Tomcat的websocket传输,注意传输内容大小。而且HTTP 2.0和HTTP 3.0 并不能使用websocket,尤其是http 3.0 UDP协议。

websocket 传输文件相关推荐

  1. websocket传输canvas图像数据给C++服务端opencv图像实现web在线实时图像处理

    为什么80%的码农都做不了架构师?>>>    前后端的耦合想了很久,上下课都在思考怎么做,然后终于憋出来了.这是之前搞的一个视觉计算的项目,boss叫对接到前端,于是就产生了这样一 ...

  2. Linux系统管理必备知识之利用ssh传输文件

    在使用SSH时候,有时我们需要传输文件,这就需要用到命令scp. 从服务器上下载文件 scp username@servername:/path/filename /local_dir(本地目录) e ...

  3. tftp:timeout问题解决 - 从Windows传输文件到开发板

    通过串口工具ping一下主机,确定是否能ping通,确保通信无问题,如下 ping通后,确保PC tftp软件打开, 检查防火墙是否关闭,专用网络是家庭网络,允许同网段下的数据传输,无需关闭,因此只需 ...

  4. 使用nc传输文件和目录【转】

    方法1,传输文件演示(先启动接收命令) 使用nc传输文件还是比较方便的,因为不用scp和rsync那种输入密码的操作了 把A机器上的一个rpm文件发送到B机器上 需注意操作次序,receiver先侦听 ...

  5. linux cp sync,通过SSH使用Rsync传输文件,复制和同步文件及目录

    在本文中,我们将解释如何通过SSH使用rsync复制文件.当涉及在网络上的系统之间传输文件时,Linux和Unix用户可以使用许多工具,最流行的数据传输协议是SSH和FTP,虽然FTP很受欢迎,但总是 ...

  6. 用 Dubbo 传输文件?被老板一顿揍

    以下文章来源方志朋的博客,回复"666"获面试宝典 公司之前有一个 Dubbo 服务,其内部封装了腾讯云的对象存储服务 SDK,目的是统一管理这种三方服务的SDK,其他系统直接调用 ...

  7. 使用C++的Socket实现从客户端到服务端,服务端到客户端传输文件

    使用: (1)首先运行服务端,待服务端运行起来: (2)最后运行客户端,输入要传输文件到哪个目标机器的IP地址: (3)输入传输文件的路径及文件(完成的路径),其中包含文件的类型,也就是后缀需要包含( ...

  8. 使用C++实现Socket编程传输文件

    使用: (1)首先运行服务端,待服务端运行起来: (2)最后运行客户端,输入要传输文件到哪个目标机器的IP地址: (3)输入传输文件的路径及文件(完成的路径),其中包含文件的类型,也就是后缀需要包含( ...

  9. python linux编程与window编程_Python实现Windows和Linux之间互相传输文件(文件夹)的方法...

    项目中需要从Windows系统传输ISO文件到Linux测试系统,然后再Linux测试系统里安装这个ISO文件.所以就需要实现如何把文件从Windows系统传输到Linux系统中. 在项目中使用了ps ...

最新文章

  1. liunx 上get 不到url参数 java_thinkphp5.0 模板上直接获取url参数
  2. 大一计算机论文_大一计算机实验报告
  3. 树莓派学习——音频视频播放
  4. horizon client 无法识别域_iText for Mac(OCR识别图中文字工具)
  5. 当我们谈微服务,我们在谈什么?谈谈我对微服务的理解!
  6. golang中获取公网ip、查看内网ip、检测ip类型、校验ip区间、ip地址string和int转换、根据ip判断地区国家运营商等
  7. matlab中lambertw,MATLAB解常微分方程
  8. 网络工程师专用linux,软考网络工程师考点精讲之Linux系统
  9. 大学计算机基础知识点
  10. CIF格式(QCIF、CIF、2CIF、4CIF、DCIF)
  11. 西藏拉姆拉错:蓝蓝的湖水
  12. 心电信号质量评估——ecg_qc工具包介绍(二)
  13. 使用starUML一步一步画顺序图
  14. Opencv3.2各个模块功能详细简介(包括与Opencv2.4的区别)
  15. 【vbs/bat】强制关闭程序
  16. 手把手QQ机器人制作教程,根据官方接口进行开发,基于Python语言制作的详细教程(更新中)
  17. PUN2多人联网之房间选择、创建房间
  18. 使用Socket实现点对点的文件传输
  19. 记事本文档转成excel
  20. Flutter MD5加密工具类

热门文章

  1. “黑洞”戳破中国版权乱象 迅雷、纸贵、京东、趣链给出区块链解决方案
  2. 15.说说你对slot的理解?slot使用场景有哪些?
  3. XML简介,XML和HTML的区别,XML用处,XML规则,XML约束,XML语法,XML解析,DOM
  4. 天气太热,给笔记本清凉一下
  5. 一键清除苹果锁屏密码_苹果iPhone 8(全网通)手机一直重启怎么办?手机忘记密码怎么一键刷机?...
  6. 2022-2028全球笔式万用表行业调研及趋势分析报告
  7. html_css_四分之一圆
  8. 2021年俄罗斯与中国双边货物进出口额及分布:中俄双边进出口额增长,贸易逆差下降,矿物产品占比最大[图]
  9. 常用命令(转http://blog.csdn.net/ljianhui/article/details/11100625/)
  10. 硬盘摔了还能恢复里面的数据吗