美文网首页
Socket编程多文件传输

Socket编程多文件传输

作者: Wpixel | 来源:发表于2018-06-26 17:19 被阅读0次

    有子曰:“其为人也孝弟,而好犯上者,鲜矣;不好犯上,而好作乱者,未之有也。君子务本,本立而道生。孝弟也者,其为仁之本与!”

    项目介绍:基于TCP协议实现多文件传输

    将F盘test文件加下的所有文件发送到D盘下的FTP文件夹里

    思路:socket发送单个文件,然后通过for循环来实现多文件传输。

    简单做法(这里就简单说下思路,没实现):

    _1) socket与服务器建立连接
    _2) 然后发送一个文件
    _3) socket断开
    _4) 循环第一步

    以上做法非常简单,但是socket建立连接时非常耗费资源的,如果有1000个文件要同时上传,那么socket就要与服务器建立1000次连接和1000次断开连接。写到这里我突然想到连接池,连接池也是一种提高的方法,虽然没有频繁的创建销毁,但是初始化的时候就占用了系统的资源,我何不创建一个socket用到系统报废呢。

    高端做法:

    所以如果你还不知道IO流的概念,那你就不能算是一个合格的程序员
    我这里简单的说一下,大神绕道
    当客户端想服务端发送数据的时候,是以byte[]的形式传输的,byte[]数组存放的是ASCII码
    比如第一次发送的是"ABC",然后紧接着又发送"abcd"
    那么服务端接受接受到的就是"ABCabcd"
    所以流是不会断开的,既然是连在一起的,那么怎么区分呢?
    那就要同时向服务端传一个长度
    比如第一次发送的是"ABC",那么在发送"ABC"之前要让服务器知道我发送的内容长度,这里发送一个int类型的3
    同理发送"abcd"之前也要发一个int类型的4,这是长度让,让服务器截取内容用的。
    然后服务器解析的时候先获取前4个字节解析长度,然后通过长度来获取内容


    _1) socket与服务器建立连接
    _2) 然后for循环发送多个文件
    _3) socket断开

    从建立连接到发送完毕断开连接,从始至终都是只有一个socket。


    先画一个流程图。(好丑啊)

    OK不废话了,开始上代码

    1.启动服务,等待客户端连接

    import java.io.BufferedInputStream;
    import java.io.ByteArrayInputStream;
    import java.io.DataInputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    import javax.swing.plaf.basic.BasicInternalFrameTitlePane.MoveAction;
    
    public class TcpSendFileServer {
    
        @SuppressWarnings("resource")
        public static void main(String[] args) {
            
            int port = 5555;
            ServerSocket server = null;
            Socket socket = null;
            try {
                server = new ServerSocket(port);
                System.out.println("======启动服务=======");
                
                String pathname = "D:\\FTP\\";
                File d = new File(pathname);
                if(!d.exists()){
                    d.mkdir();
                }
                
                //使用线程池
                ExecutorService threadPool = Executors.newFixedThreadPool(100);
                
                while(true){
                    socket = server.accept();
                    InputStream in = socket.getInputStream();
                    DataInputStream dis = new DataInputStream(in);
                    int fileNum = dis.readInt();
                    System.out.println("传输的文件总个数:"+fileNum);
                    String[] fileNames = new String[fileNum];
                    long[] fileSizes = new long[fileNum];
                    for (int i = 0; i < fileNum; i++) {
                        fileNames[i] = dis.readUTF();
                        fileSizes[i] = dis.readLong();
                        System.out.println("文件名:"+fileNames[i]);
                        System.out.println("文件大小:"+fileSizes[i]);
                    }
                    int byteNum = 1024;
                    Runnable runnable = () -> {
                        FileOutputStream fos = null;
                        try {
                            byte[] bytes = new byte[byteNum]; 
                            //储存剩下的字节
                            byte[] surplusbytes = new byte[byteNum]; 
                            int length = 0;
                            //文件剩余大小
                            int leftLen = 0;
                            int writeLen  = 0;
                            boolean flog = true;
                            int num = 0;
                            long totalWriteLens = 0;
                            
                            //没用的变量
                            int testLen = 0;
                            int pointLen = 0;
                            while(((length = dis.read(bytes, 0, bytes.length)) != -1 || surplusbytes[0] != 0) && num < fileNum){
                                if(flog){
                                    System.out.println("开始接受文件"+(num+1));
                                    File file = new File(pathname+fileNames[num]);
                                    fos = new FileOutputStream(file);
                                    totalWriteLens = 0;
                                    testLen = 0;
                                    flog = false;   
                                    if((num+1) == 6){
                                        System.out.println("=-----------------");
                                    }
                                } 
                                if(length >= (int)fileSizes[num] || surplusbytes[0] != 0){
                                    if(surplusbytes[0] != 0){
                                        testLen = surplusbytes.length - pointLen;
                                        if((int)fileSizes[num] >= testLen){
                                            fos.write(surplusbytes, 0, testLen);
                                            fos.flush();
                                            surplusbytes = new byte[byteNum];
                                            totalWriteLens += testLen;
                                        }else{
                                            fos.write(surplusbytes, 0, (int)fileSizes[num]);
                                            fos.flush();
                                            leftLen = surplusbytes.length - (int)fileSizes[num];
                                            move(surplusbytes, surplusbytes, (int)fileSizes[num] , leftLen);
                                            testLen = 0;
                                            flog = true;
                                        }
                                    }
                                    if(length >= (int)fileSizes[num] - testLen){
                                        fos.write(bytes, 0, (int)fileSizes[num] - testLen);
                                        fos.flush();
                                        pointLen = (int)fileSizes[num] - testLen;
                                        leftLen = bytes.length - (int)fileSizes[num];
                                        move(surplusbytes, bytes, (int)fileSizes[num] , leftLen);
                                    }else{
                                        if(surplusbytes[0] != 0 && !flog){
                                            fos.write(surplusbytes, 0, (int)fileSizes[num]);
                                            surplusbytes = new byte[byteNum];
                                        }
                                        if(!flog){
                                            fos.write(bytes);
                                            surplusbytes = new byte[byteNum];
                                        }
                                        fos.flush();
                                        totalWriteLens += length;
                                    }
                                    if(surplusbytes[0] != 0 || num >= fileNum){
                                        flog = true;
                                        num ++;
                                    }
                                    
                                }else{
                                    if((fileSizes[num] - totalWriteLens) / length < 1){
                                        length = (int)(fileSizes[num] - totalWriteLens);
                                    }
                                    if(surplusbytes[0] != 0){
                                        fos.write(surplusbytes, 0, leftLen);
                                        fos.flush();
                                        surplusbytes = new byte[byteNum];
                                    }
                                    fos.write(bytes, 0, length);
                                    fos.flush();
                                    leftLen = bytes.length - length;
                                    pointLen = length;
                                    move(surplusbytes, bytes, length, leftLen);
                                    if(surplusbytes[0] != 0){
                                        flog = true;
                                        num ++;
                                    }
                                    totalWriteLens += length;
                                }
                            }
                            System.out.println("==========文件传输完毕===========");
                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                if(fos != null){
                                    fos.close();
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    };
                    threadPool.execute(runnable);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                
            }
        }
        
        
        /**
         * 
         * @param surplusbytes
         * @param bytes
         * @param length 已经使用的个数
         * @param leftLen 剩下需要转移的数组个数
         */
        public static void move(byte[] surplusbytes, byte[] bytes, int length, int leftLen){
            for (int i = 0; i < leftLen; i++) {
                if(bytes[length+i] != 0){
                    surplusbytes[i] = bytes[length+i];
                }
            }
        }
    }
    

    2.客户端建立一个连接发送多文件

    import java.io.DataOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.net.Socket;
    
    public class TcpSendFileClient {
    
        public static int port = 5555;
        public static String host = "localhost";
        public static Socket socket = null;
    
        @SuppressWarnings("resource")
        public static void main(String[] args) {
            //创建socket连接
            createSocket();
            try {
                //发送文件的发放,需要文件价路径
                sendMultipleFile( "F:\\Test");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //关闭socket连接
                closeSocket();
            }
        }
    
        public static void sendMultipleFile(String path) throws Exception{
            String[] fileNames = getFileName(path);
            sendSingleFile(path, fileNames);
        }
    
        public static String[] getFileName(String path){
            File file = new File(path);
            return file.list();
        }
    
        public static File[] createFile(String path, String[] pathname){
            File[] files = new File[pathname.length];
            try {
                for (int i = 0; i < pathname.length; i++) {
                    File file = new File(path+"\\"+pathname[i]);
                    if(file.exists() && file.isFile()){
                        file.createNewFile();
                        files[i] = file;
                    }
                }
                return files;
                } catch (IOException e) {
                e.printStackTrace();
            }
            return files;
        }
    
        public static void sendSingleFile(String path, String[] pathName) throws Exception{
            File[] file = createFile(path, pathName);
            DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
    
            dos.writeInt(file.length);
            dos.flush();
            //将文件名和文件长度先发送过去
            for (int i = 0; i < file.length; i++) {
                System.out.println(file.length+"=="+file[i].getName()+"=="+file[i].length());
                dos.writeUTF(file[i].getName());
                dos.flush();
                dos.writeLong(file[i].length());
                dos.flush();
            }
        
            System.out.println("开始发送文件...");
    
            byte[] bytes = new byte[1024];   
            int length = 0;
            //发送文件内容
            for (int i = 0; i < file.length; i++) {
                FileInputStream fis = new FileInputStream(file[i]);
                while((length = fis.read(bytes, 0, bytes.length)) != -1){
                    dos.write(bytes, 0, length);
                    dos.flush();
                }
            }
            System.out.println("文件发送完毕...");
        }
    
        public static void createSocket(){
            try {
                socket = new Socket(host, port);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static void closeSocket(){
            try {
                if(socket != null){
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    3.运行结果

    客户端打印信息
    4==1.jpg==161236
    4==2.jpg==182327
    4==3.jpg==42138
    4==4.jpg==73057
    开始发送文件...
    文件发送完毕...
    ======== 文件传输结束 ========

    服务端打印信息
    ======启动服务=======
    传输的文件总个数:4
    文件名:1.jpg
    文件大小:161236
    文件名:2.jpg
    文件大小:182327
    文件名:3.jpg
    文件大小:42138
    文件名:4.jpg
    文件大小:73057
    开始接受文件1
    开始接受文件2
    开始接受文件3
    开始接受文件4
    ==========文件传输完毕===========

    成功将4个文件传送过去了



    作者是一名自由程序员,住在上海,喜欢音乐、小说、旅行、以及编程。

    P.S. 如果您喜欢这篇文章并且希望学习编程技术的话,请关注一下

    相关文章

      网友评论

          本文标题:Socket编程多文件传输

          本文链接:https://www.haomeiwen.com/subject/dnxzeftx.html