Springboot基于Socket的文件传输 JAVA客户端、服务端

该博客介绍了如何使用Java实现基于Socket的文件上传服务端和客户端。服务端通过`FileUpLoadSocketServer`类监听指定端口,接收客户端发送的文件,进行token验证,然后保存文件。客户端通过`SocketFileUpLoadClient`类建立连接,发送文件、token等信息。整个过程利用了多线程和Hutool库进行辅助操作。
摘要由CSDN通过智能技术生成

服务端

FileUpLoadSocketServer.java

import cn.hutool.jwt.JWTUtil;
import server.constant.ServerConstant;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;



public class FileUpLoadSocketServer {

    private final Logger logger = LoggerFactory.getLogger(FileUpLoadSocketServer.class);

    private final int POOL_SIZE = 4;
    //服务套接字等待对方的连接和文件发送
    private ServerSocket serverSocket;

    private String token;

    private String uploadPath;

    private int report;
    /**
     * description 线程池
     */
    private ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE);

    public FileUpLoadSocketServer(int report, String uploadPath, String token) throws IOException {
        this.uploadPath = uploadPath;
        this.report = report;
        this.token = token;
    }


    /**
     * 使用线程处理每个客户端传输的文件
     *
     * @throws Exception
     */
    public void load() throws Exception {
        serverSocket = new ServerSocket(report);
        Socket socket = null;
        while (true) {
            try {
                socket = serverSocket.accept();
                executorService.execute(new Task(socket));
            } catch (Exception e) {
                logger.error("服务开启失败!", e);
            }
        }
    }


    /**
     * 处理客户端传输过来的文件线程类
     */
    class Task implements Runnable {

        //当前连接
        private Socket socket;

        public Task(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            logger.info("新连接 " + socket.getInetAddress() + ":" + socket.getPort());
            DataInputStream dis = null;
            DataOutputStream dos = null;
            int bufferSize = 8192;
            String fileName = null;
            byte[] buf = new byte[bufferSize];
            try {
                dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
                String clientToken = dis.readUTF();
                //logger.info("clientToken",clientToken);
                if (!JWTUtil.verify(clientToken, token.getBytes())) {
                    dis.close();
                    throw new RuntimeException("token验证失败,断开连接!");
                }
                fileName = dis.readUTF();
                //logger.info("fileName",fileName);
                String saveFilePath = dis.readUTF();
                //logger.info("saveFilePath",saveFilePath);
                long fileLength = dis.readLong();
                if (StringUtils.isEmpty(saveFilePath)) {
                    saveFilePath = uploadPath;
                }
                //不存在文件夹就创建文件夹
                File file = new File(saveFilePath);
                if(!file.exists()){
                    file.mkdirs();
                }
                String savePath = saveFilePath + File.separatorChar + fileName;
                //File file = new File(saveFilePath);
                //if (file.exists()) {
                //    dis.close();
                //    throw new RuntimeException("文件已存在,断开连接!");
                //}
                dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(savePath)));
                logger.info("文件: " + FormatUtil.formatSize(fileLength) + " " + saveFilePath);
                int read = 0;
                long passedlen = 0;
                long i = 0;
                fileStateCahe.put(fileName, ServerConstant.FILE_STATE.FILE_UPLOAD_UPLOADING);
                while ((read = dis.read(buf)) != -1) {
                    passedlen += read;
                    dos.write(buf, 0, read);
                    //if (i < (passedlen * 100L / fileLength)) {
                    //    i = passedlen * 100L / fileLength;
                    //    logger.info("文件已经接收: " + i + "%");
                    //}
                }
                logger.info("文件[" + savePath + "]接收完成!");
                fileStateCahe.put(fileName, ServerConstant.FILE_STATE.FILE_UPLOAD_COMPLETED);
            } catch (RuntimeException e) {
                fileStateCahe.put(fileName, ServerConstant.FILE_STATE.FILE_UPLOAD_FAILED);
                logger.error("接收失败!", e);
            } catch (Exception e) {
                fileStateCahe.put(fileName, ServerConstant.FILE_STATE.FILE_UPLOAD_FAILED);
                logger.error("接收失败!", e);
            } finally {
                try {
                    if (dos != null) {
                        dos.close();
                    }
                    if (dis != null) {
                        dis.close();
                    }
                    if (socket != null) {
                        socket.close();
                    }
                } catch (Exception e) {
                    logger.error("", e);
                }
            }
        }
    }
}

ServerConstant.java


import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import org.apache.commons.lang3.ObjectUtils;


public interface ServerConstant {
    /**
     * 上传完成
     */
    public static final int FILE_UPLOAD_COMPLETED = 21001;

    /**
     * 上传中
     */
    public static final int FILE_UPLOAD_UPLOADING = 21002;

    /**
     * 上传失败
     */
    public static final int FILE_UPLOAD_FAILED = 21003;

    /**
     * 文件未查询到
     */
    public static final int FILE_NOT_FIND = 21004;

    /**
     * description 保存文件上传状态
     */
    public static Cache<String, FILE_STATE> fileStateCahe = CacheUtil.newFIFOCache(100);

    /**
     * 文件状态enum
     */
    public static enum FILE_STATE {
        /**
         * 文件上传完成
         */
        FILE_UPLOAD_COMPLETED,
        /**
         * 文件上传中
         */
        FILE_UPLOAD_UPLOADING,
        /**
         * 文件上传失败
         */
        FILE_UPLOAD_FAILED,
        /**
         * 文件未找到
         */
        FILE_NOT_FIND,
        /**
         * 文件已存在
         */
        FILE_EXSIT,
        /**
         * 文件准备开始传输
         */
        FILE_UPLOAD_START
    }
}

SocketServerListener.java

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @ClassName SocketServerListener
 * @date 2022/06/15 09:43:52
 */
public class SocketServerListener 

 private static final Logger logger = LoggerFactory.getLogger(SocketServerListener.class);

    private int socketServerPort;

    private String socketStatus;

    private String uploadPath;

    private String token;

    public SocketServerListener(int socketServerPort, String socketStatus, String uploadPath,String token) {
        this.socketServerPort = socketServerPort;
        this.socketStatus = socketStatus;
        this.uploadPath = uploadPath;
        this.token = token;
    }

    //  初始化启动Socket服务
    @Async
    public void init() throws Exception {
        if (ServerConstant.OPEN.equals(socketStatus)) {
            open();
        }
    }

    public void open() throws Exception {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @SuppressWarnings("resource")
            @Override
            public void run() {
                try {
                    FileUpLoadSocketServer fileUpLoadSocketServer = new FileUpLoadSocketServer(socketServerPort, uploadPath,token);
                    fileUpLoadSocketServer.load();
                    logger.info("FileUpLoadSocketServer 启动成功!");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, 3000);

    }
}

startSocketServer.java

@Component
public class startSocketServer {

    private final Logger logger = LoggerFactory.getLogger(StartSocketServer.class);

    @Autowired
    private ServerConfig serverConfig;

    @Bean
    public void startServerListener()  {
        try {
            SocketServerListener socketServerListener = new SocketServerListener();
            socketServerListener.init();
            System.out.println("启动成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

ServerConfig.java

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

//读取yml配置
@Configuration
@ConfigurationProperties(prefix = "base.server")
public class ServerConfig {

    private String communicationToken ;

    private String defaultUploadPath;

    private int socketServerPort;

    private String socketStatus;

    public String getCommunicationToken() {
        return communicationToken;
    }

    public void setCommunicationToken(String communicationToken) {
        this.communicationToken = communicationToken;
    }

    public String getDefaultUploadPath() {
        return defaultUploadPath;
    }

    public void setDefaultUploadPath(String defaultUploadPath) {
        this.defaultUploadPath = defaultUploadPath;
    }

    public int getSocketServerPort() {
        return socketServerPort;
    }

    public void setSocketServerPort(int socketServerPort) {
        this.socketServerPort = socketServerPort;
    }

    public String getSocketStatus() {
        return socketStatus;
    }

    public void setSocketStatus(String socketStatus) {
        this.socketStatus = socketStatus;
    }


}

yml

#自定义配置参数
base:
  server:
    #通信token,server client保持一致
    communicationToken: communicationToken
    #默认备份位置
    defaultUploadPath: E:\Code\xyhz\wwwBackup
    #socket文件传输服务端端口号
    socketServerPort: 10086
    #socket文件传输服务端状态
    socketStatus: open

pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.0.M2</version>
        </dependency>

客户端

SocketFileUpLoadClient.java


import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/** 
 * @date 2022/06/15 09:41:50
 */
@Slf4j
public class SocketFileUpLoadClient {

    public SocketFileUpLoadClient(String token, String filePath, String ip, Integer report, String saveFilePath) {
        ExecutorService taskScheduler = Executors.newCachedThreadPool();
        taskScheduler.execute(sendFile(token, filePath, ip, report, saveFilePath));
    }

    private static Runnable sendFile(String token, String filePath, String ip, int port, String saveFilePath) {
        return new Runnable() {
            private Socket socket = null;

            @Override
            public void run() {
                File file = new File(filePath);
                if (file.exists()) {
                    if (createConnection()) {
                        int bufferSize = 8192;
                        byte[] buf = new byte[bufferSize];
                        try {
                            DataInputStream fis = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath)));
                            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
                            dos.writeUTF(token);
                            dos.flush();
                            //log.info("token:" + token);
                            dos.writeUTF(file.getName());
                            dos.flush();
                            //log.info("file.getName():" + file.getName());
                            dos.writeUTF(saveFilePath);
                            dos.flush();
                            //log.info("saveFilePath:" + saveFilePath);
                            dos.writeLong(file.length());
                            dos.flush();
                            int read = 0;
                            int passedlen = 0;
                            //获得要发送文件的长度
                            long length = file.length();
                            long i = 0;
                            log.info("开始发送文件:" + filePath);
                            long start = System.currentTimeMillis();
                            while ((read = fis.read(buf)) != -1) {
                                passedlen += read;
                                //if (i < passedlen * 100L / length) {
                                //    i = (passedlen * 100L / length);
                                //    log.info("已经发送文件: " + i + "%");
                                //}
                                dos.write(buf, 0, read);
                                dos.flush();
                            }
                            dos.flush();
                            fis.close();
                            dos.close();
                            socket.close();
                            log.info(FormatUtil.formatMillisecond(System.currentTimeMillis() - start) + "文件传输完成![" + filePath + "]" + FormatUtil.formatSize(length));
                        } catch (Exception e) {
                            log.error("文件传输失败!", e);
                        }
                    }
                } else {
                    log.error("文件不存在[" + filePath + "]");
                }
            }

            private boolean createConnection() {
                try {
                    socket = new Socket(ip, port);
                    log.info("连接服务器成功!" + ip + ":" + port);
                    return true;
                } catch (Exception e) {
                    log.error("连接服务器失败!", e);
                    return false;
                }
            }
        };
    }
}

客户端启动

 public static void main(String[] args) {
          DateTime now = DateTime.now();
        DateTime newTime = now.offsetNew(DateField.MINUTE, 10);
        Map<String, Object> map = new HashMap<String, Object>();
        //签发时间
        map.put(JWTPayload.ISSUED_AT, now);
        //过期时间
        map.put(JWTPayload.EXPIRES_AT, newTime);
        //生效时间
        map.put(JWTPayload.NOT_BEFORE, now);
        map.put("uid", Integer.parseInt("123"));
        map.put("expire_time", System.currentTimeMillis() + 1000 * 60 * 60 * 3);
        SocketFileUpLoadClient fileUpLoadSocketClient =
                new SocketFileUpLoadClient(
                        JWTUtil.createToken(map,"communicationToken".getBytes()),
                        "F:\\OS\\cn_windows_server_2019_essentials_x64_dvd_5b386b0b.iso",
                        "127.0.0.1", 10010,"F:\\");
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值