[特殊字符]【高并发实战】Java Socket + 线程池实现高性能文件上传服务器(附完整源码)[特殊字符]

发布于:2025-04-11 ⋅ 阅读:(36) ⋅ 点赞:(0)

大家好!今天给大家分享一个 Java Socket + 线程池 实现的高性能文件上传服务器,支持 多客户端并发上传,代码可直接运行,适合 面试、项目实战、性能优化 学习!

📌 本文亮点:

  • ✅ 完整可运行代码(附详细注释)

  • ✅ 线程池优化(拒绝策略、队列控制)

  • ✅ UUID 生成唯一文件名(避免冲突)

  • ✅ 客户端/服务器完整交互流程

  • ✅ 适合新手进阶 & 面试加分项

如果你对 Java网络编程、高并发、线程池 感兴趣,这篇一定要看!👇


🚀 1. 项目背景

在实际开发中,我们经常需要实现 文件上传 功能,比如:

  • 用户上传头像

  • 日志文件收集

  • 分布式系统数据传输

如果直接用 单线程 Socket,服务器只能 一个一个处理请求,性能极差!

💡 解决方案:
✅ 多线程:每个客户端连接分配一个线程
✅ 线程池:避免频繁创建/销毁线程,提升性能
✅ 非阻塞IO(NIO):更高性能(本文先讲基础版)


💻 2. 代码实现

📌 服务器端(支持多客户端并发上传)

import java.io.*;
import java.net.*;
import java.util.UUID;
import java.util.concurrent.*;

public class FileUploadServer {
    public static void main(String[] args) throws IOException {
        // 创建线程池(核心3线程,最大16线程,队列容量2,60秒空闲回收)
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
            3, 16, 60, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(2),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy()  // 队列满时拒绝新任务
        );

        ServerSocket server = new ServerSocket(10086);
        System.out.println("⚡服务器启动,等待客户端连接...");

        while (true) {
            Socket socket = server.accept();  // 阻塞等待客户端连接
            pool.submit(new FileUploadHandler(socket));  // 提交任务到线程池
            System.out.println("🔗 客户端连接: " + socket.getInetAddress());
        }
    }
}

class FileUploadHandler implements Runnable {
    private final Socket socket;

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

    @Override
    public void run() {
        try (
            InputStream is = socket.getInputStream();
            OutputStream os = socket.getOutputStream();
        ) {
            // 生成唯一文件名(避免冲突)
            String fileName = UUID.randomUUID() + ".jpg";
            
            // 写入本地文件
            try (FileOutputStream fos = new FileOutputStream(fileName)) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = is.read(buffer)) != -1) {
                    fos.write(buffer, 0, len);
                }
                System.out.println("📁 文件保存成功: " + fileName);
            }

            // 返回响应给客户端
            os.write("✅ 上传成功!".getBytes());
            os.flush();
        } catch (IOException e) {
            System.err.println("❌ 处理异常: " + e.getMessage());
        } finally {
            try {
                socket.close();  // 关闭连接
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

📌 客户端(上传文件)

import java.io.*;
import java.net.*;

public class FileUploadClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("localhost", 10086);  // 连接服务器
        System.out.println("🚀 连接服务器成功!");

        // 读取本地文件并发送
        try (
            FileInputStream fis = new FileInputStream("test.jpg");
            OutputStream os = socket.getOutputStream();
            InputStream is = socket.getInputStream();
        ) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            System.out.println("📤 文件发送完成!");

            // 接收服务器响应
            byte[] response = new byte[1024];
            int responseLen = is.read(response);
            System.out.println("📥 服务器响应: " + new String(response, 0, responseLen));
        } finally {
            socket.close();
        }
    }
}

📊 3. 关键优化点

✅ 1. 线程池管理

  • 核心线程数 = 3(保持活跃)

  • 最大线程数 = 16(应对突发流量)

  • 队列容量 = 2(防止资源耗尽)

  • 拒绝策略 = AbortPolicy(队列满时直接拒绝)

✅ 2. 唯一文件名生成

String fileName = UUID.randomUUID() + ".jpg";  // 避免文件名冲突

✅ 3. 资源自动关闭

使用 try-with-resources,确保 SocketFileOutputStream 等资源自动释放,避免内存泄漏!


🚀 4. 如何运行?

  1. 启动服务器

    java FileUploadServer
  2. 启动客户端(可开多个):

    java FileUploadClient
  3. 查看结果

    • 服务器控制台显示客户端连接和文件保存路径

    • 客户端收到 上传成功 响应


💡 5. 扩展优化

  • NIO(Non-blocking IO):更高性能(Netty 底层实现)

  • 断点续传:记录文件偏移量

  • 加密传输:SSL/TLS 安全传输

  • 分布式存储:上传到云存储(OSS)


📌 6. 总结

  • 本文实现了一个高并发文件上传服务器,适合 面试、项目实战

  • 关键点:线程池、Socket、资源管理、UUID 文件名

  • 优化方向:NIO、断点续传、加密传输

如果觉得有用,点赞 👍 + 关注 ➕,后续更新更多 Java 高并发实战!

📢 互动话题:
你在项目中遇到过文件上传的问题吗?欢迎评论区讨论!👇

#Java #Socket #多线程 #高并发 #文件上传 #面试必备

public class MyRunable implements Runnable{


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

    @Override
    public void run() {


        try {
            // 接收文件
            BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
            String name = UUID.randomUUID().toString().replace("-", "");
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(name + ".jpg"));

            byte[] bytes = new byte[1024];
            int len;
            while ((len = bis.read(bytes)) != -1) {
                bos.write(bytes, 0, len);
            }
            bos.flush();
            bos.close();  // 关闭文件输出流

            // 发送响应给客户端
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bw.write("上传成功");
            bw.newLine();
            bw.flush();

            // 先关闭输出流,再关闭socket
            socket.shutdownOutput();

        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }


        }
    }}


public class reserve {
    public static void main(String[] args) throws IOException {

        ThreadPoolExecutor pool=new ThreadPoolExecutor(
                3,//核心线程数量
                16,//线程池总大小
                60,//空闲时间
                TimeUnit.SECONDS,//空闲时间单位
                new ArrayBlockingQueue<>(2),//队列
                Executors.defaultThreadFactory(),//线程工场,让线程池如何创建对象
                new ThreadPoolExecutor.AbortPolicy()//阻塞队列
        );


        ServerSocket ss = new ServerSocket(10086);


        while (true) {
            Socket socket = ss.accept();
pool.submit(new MyRunable(socket));


        }

    }
}

public class Main {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("192.168.129.132", 10086);

        // 发送文件
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("微信图片_20250303192811.jpg"));
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

        byte[] bytes = new byte[1024];
        int len;
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
        bos.flush();
        socket.shutdownOutput();  // 告诉服务器数据发送完毕

        // 接收服务器响应
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String response = br.readLine();
        System.out.println("服务器响应: " + response);

        // 关闭资源
        bis.close();
        br.close();
        socket.close();
    }
}