Java | Socket 文件服务器(swing界面) 实现客户端与服务器的文件传输

2,776 阅读2分钟

前言

  • 基于Socket的TCP协议简单实现客户端和服务器之间的文件传输,实现上传,下载文件。

效果:

  • 客户端: 客户端界面
  • 服务端:  

思路:

客户端:

  • 打开客户端后,发送读取服务器文件列表消息给服务器,然后服务器把文件列表返回返回,然后客户端再在界面上显示即可。之后客户端可进行下载,上传文件,刷新文件列表操作。所以客户端这里有三种类型消息,为了能方便服务器识别客户端消息的类型然后进行相应处理,简单规范化双方通信协议。如下:然后要进行相应操作发送相应消息给服务器即可。
通信格式:
        1) 下载文件消息格式:@action=Download["fileName":"fileSize":"result"]
            参数说明:
                fileName 要下载的文件的名字
                fileSize 要下载的文件的大小
                result 下载许可

       2)   上传文件消息格式: @action=Upload["fileName":"fileSize":result]
             参数说明:
                    fileName   要上传的文件的名字
 *                  fileSize   要上传的文件的大小
                    result     上传许可
       3)返回文件列表格式
 *;               @action=GroupFileList["fileName1":"fileName2":"fileName3"...]

服务端:

  • 服务端负责处理客户端的各种消息,比如请求下载消息@action=Download["fileName":"fileSize":"result"],把客户端请求下载的文件名解析出来,服务器端判断是否存在该文件,并把结果按请求下载消息把文件大小和下载许可返回客户端,若存在该文件,然后服务器打开对客户端的输出流输出文件,客户端接收到许可消息后,打开对服务器的输入流读取文件。

源码

服务器代码

  • 一些文件的保存和读取路径目录,需根据自己项目目录结构更改
public class FileServer {
    private final int port = 5203;
    private ServerSocket server_socket;   //普通消息传输服务器套接字
    private ServerSocket fileServerSocket;  // 文件传输服务器套接字

    private String path ="文件服务器/GroupFile"; //服务器文件保存路径

    public FileServer() {
        try {
            //1-初始化
            server_socket = new ServerSocket(this.port);   // 创建消息传输服务器
            fileServerSocket = new ServerSocket(8888);  //创建文件传输服务器

              System.out.println("文件服务器启动等待客户端连接.....");
            //2-每次接收一个客户端请求连接时都启用一个线程处理
            while(true) {
                Socket client_socket = server_socket.accept();
                 System.out.println("客户端:"+client_socket.getRemoteSocketAddress()+"已连接");
                new ServerThread(client_socket).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /** -----------------------------------------------------------------------------------------------------
     *
     *   启用一个线程处理客户端的请求
     */
    private class ServerThread extends Thread{
        private Socket client_socket;
        private BufferedReader server_in;
        private PrintWriter server_out;

        public ServerThread(Socket client_socket) {
            try {
                //初始化
                this.client_socket = client_socket;
                server_in = new BufferedReader(new InputStreamReader(this.client_socket.getInputStream()));
                server_out = new PrintWriter(this.client_socket.getOutputStream(),true);


            } catch (IOException e) {
            }
        }

        public void run() {
            try {
                String uploadFileName = null;
                String uploadFileSize = null;
                String fromClientData ;

                while((fromClientData = server_in.readLine()) != null){
                        //把服务器文件列表返回
                        if(fromClientData.startsWith("@action=loadFileList")){
                            File dir = new File(path);
                            if (dir.isDirectory()){
                                String[] list = dir.list();
                                String filelist = "@action=GroupFileList[";
                                for (int i = 0; i < list.length; i++) {
                                    if (i == list.length-1){
                                        filelist  = filelist + list[i]+"]";
                                    }else {
                                        filelist  = filelist + list[i]+":";
                                    }
                                }
                                server_out.println(filelist);
                            }
                        }

                        //请求上传文件
                        if (fromClientData.startsWith("@action=Upload")){
                            uploadFileName = ParseDataUtil.getUploadFileName(fromClientData);
                            uploadFileSize = ParseDataUtil.getUploadFileSize(fromClientData);
                            File file = new File(path,uploadFileName);
                            //文件是否已存在
                            if (file.exists()){
                                //文件已经存在无需上传
                                server_out.println("@action=Upload[null:null:NO]");
                            }else {
                                //通知客户端开可以上传文件
                                server_out.println("@action=Upload["+uploadFileName+":"+uploadFileSize+":YES]");
                                //开启新线程上传文件
                                new HandleFileThread(1,uploadFileName,uploadFileSize).start();
                            }
                        }

                        //请求下载文件
                        if(fromClientData.startsWith("@action=Download")){
                            String fileName = ParseDataUtil.getDownFileName(fromClientData);
                            File file = new File(path,fileName);
                            if(!file.exists()){
                                server_out.println("@action=Download[null:null:文件不存在]");
                            }else {
                                //通知客户端开可以下载文件
                                server_out.println("@action=Download["+file.getName()+":"+file.length()+":OK]");
                                //开启新线程处理下载文件
                                new HandleFileThread(0,file.getName(),file.length()+"").start();
                                
                            }
                        }
                    }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        /**
         *     文件传输线程
         */
        class HandleFileThread extends Thread{
            private String filename;
            private String filesize;
            private int mode;  //文件传输模式

            public HandleFileThread(int mode,String name,String size){

                    filename = name;
                    filesize = size;
                    this.mode = mode;
            }

            public void run() {
                try {
                    Socket socket = fileServerSocket.accept();
                    //上传文件模式
                    if(mode == 1){
                        //开始接收上传
                        BufferedInputStream file_in = new BufferedInputStream(socket.getInputStream());
                        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(path,filename)));

                        int len;
                        byte[] arr = new byte[8192];

                        while ((len = file_in.read(arr)) != -1){
                            bos.write(arr,0,len);
                            bos.flush();
                        }
                        server_out.println("@action=Upload[null:null:上传完成]");
                        server_out.println("\n");
                        bos.close();
                    }

                    //下载文件模式
                    if(mode == 0){
                       BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File(path,filename)));
                       BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

                       System.out.println("服务器:开始下载");
                       int len;
                       byte[] arr =new byte[8192];
                       while((len = bis.read(arr)) != -1){
                           bos.write(arr,0,len);
                           bos.flush();
                       }

                       socket.shutdownOutput();
                    }
 					
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
	//启动程序
    public static void main(String[] args) {
        new FileServer();
    }
}

客户端代码

  • 文件列表显示图标fileIconPath自行提供设置,亦可删除
public class GroupFileView extends JFrame {
    private int width = 400;
    private int height = 600;

    private JLabel groupLabel;
    private JButton uploadButton;
    private JLabel flushLabel;
    private String fileIconPath = "文件客户端/resource/file-min.png";
    private JScrollPane jScrollPane;
    private JPanel staffPanel;      //在JSpanel上的panel

    private Socket client_socket;
    private PrintStream client_out;
    private BufferedReader client_in;
    private String ip = "127.0.0.1";
    private int port = 5203;

    private File currentUpploadFile;
    private String downloadSavePath;
    private int Y = 0;


    public GroupFileView() {
        //1-初始化
        initVariable();
        //2-连接服务器
        connectServer();
        //3-注册监听
        registerListener();
		//4-初始化窗口设置
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(width,height);
        this.setTitle("群文件");
        this.setLocationRelativeTo(null);//窗口居中显示
        this.setResizable(false);
        this.setVisible(true);
    }




    private void initVariable() {
        jScrollPane = new JScrollPane();
        this.getContentPane().add(jScrollPane);

        staffPanel = new JPanel();
        ///staffPanel.setLayout(new BoxLayout(staffPanel,BoxLayout.Y_AXIS));
        staffPanel.setLayout(null);
        staffPanel.setOpaque(false);
        staffPanel.setPreferredSize(new Dimension(width,height));

        jScrollPane.setViewportView(staffPanel);
        jScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);//设置水平滚动条隐藏
        jScrollPane.getViewport().setOpaque(false);  //设置透明
        jScrollPane.setOpaque(false);  //设置透明

        renderTop();
    }


    /**
     *      向服务器重新读取群文件列表
     */
    private void loadGroupFile() {
            client_out.println("@action=loadFileList");
    }


    /**
     *   渲染顶部面板
     */
    private void renderTop(){
        staffPanel.removeAll();
        Y = 0;
        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(1,3,3,10));
        this.groupLabel = new JLabel("\t\t\t\t\t群文件列表 ");
        this.uploadButton = new JButton("上传文件 ");
        flushLabel = new JLabel(new ImageIcon("聊天室客户端/resource/flush.png"));
        panel.add(groupLabel);
        panel.add(uploadButton);
        panel.add(flushLabel);

        panel.setBounds(2,Y,width,30);
        this.staffPanel.add(panel);
        Y += 30;
    }
    /**
         渲染文件列表
     */
    public  void addToFileList(String filename){
        JLabel fileicon = new JLabel(new ImageIcon(fileIconPath));
        JButton downloadBtn = new JButton("下载");
        JLabel fileNameLab = new JLabel(filename);

        JPanel panel = new JPanel();
        panel.setLayout(new GridLayout(1,3,0,0));
        panel.add(fileicon);
        panel.add(fileNameLab);
        panel.add(downloadBtn);
        //panel.setBorder(BorderFactory.createLineBorder(Color.BLACK));

        panel.setBounds(2,Y,width,30);
        this.staffPanel.add(panel);
        Y+=30;

        panel.addMouseListener(new MouseAdapter() {
            //鼠标移入时
            public void mouseEntered(MouseEvent e) { // 鼠标移动到这里的事件
                panel.setBackground(Color.orange);
                panel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); // 让鼠标移动到
            }
            public void mouseExited(MouseEvent e) { // 鼠标离开的事件
                panel.setBackground(Color.white);
            }

        });

        //文件下载
        downloadBtn.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                 //1-选择下载保存的位置
                JFileChooser f = new JFileChooser(); // 查找文件
                f.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                f.showOpenDialog(null);
                File file = f.getSelectedFile();

                if(file != null){
                    downloadSavePath  = file.getPath();
                    //向服务器请求下载
                    client_out.println("@action=Download["+filename+":null:null]");
                }
            }
        });
    }
    /**
     *   注册监听
     */
    private void registerListener() {
        //上传文件    消息格式: @action=Upload["fileName":"fileSize":result]
        this.uploadButton.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                JFileChooser f = new JFileChooser(); // 查找文件
                f.showOpenDialog(null);
                currentUpploadFile = f.getSelectedFile();
                if(currentUpploadFile != null)
                client_out.println("@action=Upload["+currentUpploadFile.getName()+":"+currentUpploadFile.length()+":null]");

            }
        });

        //刷新文件列表按钮
        flushLabel.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                loadGroupFile();
            }
            //鼠标移入时
            public void mouseEntered(MouseEvent e) { // 鼠标移动到这里的事件
                flushLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); // 让鼠标移动到
            }
        });
    }

    /**
     *  连接服务器
     */
    private void connectServer(){
        //连接服务器
        try {
            //初始化
            client_socket = new Socket(ip,port);
            client_out = new PrintStream(client_socket.getOutputStream(),true);
            client_in = new BufferedReader(new InputStreamReader(client_socket.getInputStream()));

            //读取文件列表
            client_out.println("@action=loadFileList");

            //开启线程监听服务器消息
            new ClientThread().start();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    /**
     *    监听服务器消息
     */
    class ClientThread extends Thread{
        public void run() {
            try {
                String fromServer_data;
                int flag = 0;

                while((fromServer_data=client_in.readLine()) != null){
                        //读取群文件列表
                        if(flag++ == 0){
                            if (fromServer_data.startsWith("@action=GroupFileList")){
                                String[] fileList = ParseDataUtil.getFileList(fromServer_data);
                                for (String filename : fileList) {
                                    addToFileList(filename);
                                }
                            }
                            continue;
                        }
                        if(fromServer_data.startsWith("@action=GroupFileList")){
                            //重新渲染顶部面板
                            renderTop();

                            //注册监听
                            registerListener();

                            //渲染文件面板
                            String[] fileList = ParseDataUtil.getFileList(fromServer_data);
                            for (String filename : fileList) {
                                addToFileList(filename);
                            }

                        }

                        //文件上传
                        if (fromServer_data.startsWith("@action=Upload")){
                            String res = ParseDataUtil.getUploadResult(fromServer_data);
                            if("NO".equals(res)){
                                JOptionPane.showMessageDialog(null,"文件已存在!");
                            }else if ("YES".equals(res)){
                                //开始上传
                                if(currentUpploadFile != null){
                                    //开启新线程传输文件
                                    new HandelFileThread(1).start();
                                }

                            }else if ("上传完成".equals(res)){
                                JOptionPane.showMessageDialog(null,res);
                                loadGroupFile();
                            }
                        }

                        //文件下载
                        if(fromServer_data.startsWith("@action=Download")){
                            String res = ParseDataUtil.getDownResult(fromServer_data);
                            if(res.equals("文件不存在")){
                                JOptionPane.showMessageDialog(null,"该文件不存在404");
                            }else {
                                String downFileName = ParseDataUtil.getDownFileName(fromServer_data);
                                String downFileSize = ParseDataUtil.getDownFileSize(fromServer_data);
                                //开启新线程传输文件
                                new HandelFileThread(0,downFileName,downFileSize).start();
                            }
                        }
                    }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        /**----------------------------------------------------------------------------------
         *     文件传输线程
         */
        class HandelFileThread extends Thread{
            private int mode;  //文件传输模式  1-上传  2-下载
            private String filename;
            private Long fileSize;

            public HandelFileThread(int mode) {
                this.mode = mode;
            }
            public HandelFileThread(int mode,String filename,String fileSize){
                this.mode = mode;
                this.filename = filename;
                this.fileSize = Long.parseLong(fileSize);
            }

            public void run() {
                try {
                    //上传文件模式
                    if(this.mode == 1){
                        Socket socket = new Socket(ip,8888);
                        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(currentUpploadFile));
                        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

                        int len;
                        int i = 0;
                        double sum = 0;
                        byte[] arr = new byte[8192];
                        String schedule;

                        System.out.println("开始上传--文件大小为:"+currentUpploadFile.length());

                        while((len = bis.read(arr)) != -1){
                            bos.write(arr,0,len);
                            bos.flush();
                            sum += len;
                            if (i++ %100 == 0){
                                schedule = "上传进度:"+100*sum/currentUpploadFile.length()+"%";
                                System.out.println(schedule);
                            }
                        }
                        //上传完成
                        socket.shutdownOutput();
                        System.out.println("上传进度:100%");
                    }

                    //下载文件模式
                    if(this.mode == 0){
                        Socket socket = new Socket(ip,8888);
                        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
                        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(downloadSavePath+"/"+filename));

                        int len;
                        byte[] arr =new byte[8192];
                        double sumDown = 0;
                        int i = 0;

                        System.out.println("客户端开始下载 ");
                        while ((len = bis.read(arr)) != -1){
                            sumDown += len;
                            if(i++%100 == 0)
                                System.out.println("下载进度为:"+100*sumDown/fileSize+"%");

                            bos.write(arr,0,len);
                            bos.flush();
                        }

                        bos.close();
                        bis.close();
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
	//启动程序
    public static void main(String[] args) throws Exception {
       new GroupFileView();
    }

消息解析工具:

public class ParseDataUtil {
 /**
     *
     * 下载文件消息格式: @action=Download["fileName":"fileSize":"result"]
     * 参数说明:
     *        fileName   要下载的文件的名字
     *        fileSize   要下载的文件的大小
              result     下载许可
     */
    public static String getDownFileName(String data){
        return data.substring(data.indexOf("[")+1,data.indexOf(":"));
    }
    public static String getDownFileSize(String data){
        return data.substring(data.indexOf(":")+1,data.lastIndexOf(":"));
    }
    public static String getDownResult(String data){
        return data.substring(data.lastIndexOf(":")+1,data.length()-1);
    }



    /**
     *
     *    上传文件消息格式: @action=Upload["fileName":"fileSize":result]
          参数说明:
     *          fileName   要上传的文件的名字
     *          fileSize   要上传的文件的大小
                result     上传许可
     */
    public static String getUploadFileName(String data){
        return data.substring(data.indexOf("[")+1,data.indexOf(":"));
    }
    public static String getUploadFileSize(String data){
        return data.substring(data.indexOf(":")+1,data.lastIndexOf(":"));
    }
    public static String getUploadResult(String data){
        return data.substring(data.lastIndexOf(":")+1,data.length()-1);
    }

    /**  返回文件列表格式
     @action=GroupFileList["fileName":"fileName":"fileName"...]
     */
    public static String[] getFileList(String data){
        String list = data.substring(data.indexOf("[")+1,data.length()-1);
        return  list.split(":");
    }
}

赞赏

                                                                                            

如果觉得文章有用,你可鼓励下作者 如果浪费你时间了,在这里先跟你抱歉