文件上传及线程优化

文件上传分析图解

\1. 【客户端】输入流,从硬盘读取文件数据到程序中。

\2. 【客户端】输出流,写出文件数据到服务端。

\3. 【服务端】输入流,读取文件数据到服务端程序。

\4. 【服务端】输出流,写出文件数据到服务器硬盘中。

\5. 【服务端】获取输出流,回写数据。

\6. 【客户端】获取输入流,解析回写数据。

服务器端实现:(优化之前)

步骤分析:

  1. 创建ServerSocket服务端对象,绑定端口
  2. 等待客户端连接:accept
  3. 获取网络输入流,接收客户端发送过来的文件数据:getInputStream
  4. 创建本地的输出,用来保存接收到的文件数据到硬盘中
  5. 边读,边写
  6. 获取网络输出流,告诉客户端发送数据完毕
  7. 释放资源
package com.test.test03;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws IOException {
        //1.创建ServerSocket服务端对象,绑定端口
        ServerSocket serverSocket=new ServerSocket(8888);

        //2.等待客户端连接:accept
        System.out.println("等待客户端连接...");
        Socket socket = serverSocket.accept();
        System.out.println("客户端连接成功!");

        //3.获取网络输入流,接收客户端发送过来的文件数据
        InputStream netIn = socket.getInputStream();
        //4.创建本地的输出,用来保存接收到的文件数据到硬盘
        FileOutputStream localOut = new FileOutputStream("G:/Server/car.jpg");

        //5.边读,边写,开始上传
        System.out.println("开始上传数据");
        byte[] bytes = new byte[1024];
        int len;
        while ((len=netIn.read(bytes))!=-1){//读取客户端发过来的文件
            localOut.write(bytes,0,len);//将数据写到硬盘中
        }
        System.out.println("上传结束");

        //6.获取网络的输出流,告诉客户端存储数据完毕
        OutputStream netOut = socket.getOutputStream();
        netOut.write("上传成功".getBytes());

        //7.释放资源
        localOut.close();
        socket.close();
        serverSocket.close();
    }
}

客户端实现:

步骤分析:

  1. 先创建客户端Socket对象指定服务器端的ip和端口
  2. 获取本地的输入流,关联要上传的文件
  3. 获取网络的输出流,发送文件数据到服务端
  4. 边读,边写
  5. 当传输完成,要告诉服务端数据传输完毕:socket.shutdownOutput();
  6. 获取网络的输入流,获取服务端发送的数据
  7. 上传完成,释放资源
package com.test.test03;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Client {
    public static void main(String[] args) throws IOException {
        //1.先创建客户端Socket对象并指定服务器端的IP和端口
        Socket socket = new Socket("127.0.0.1", 8888);
        System.out.println("连接服务器成功!");

        //2.获取本地的输入流,关联要上传的文件 读取
        FileInputStream localIn = new FileInputStream("E:/car.jpg");

        //3.获取网络的输出流,发送文件数据到服务端
        OutputStream netOut = socket.getOutputStream();

        //4.边读边写,开始发送到服务端
        System.out.println("开始上传数据");
        byte[] bytes = new byte[1024];
        int len;
        while ((len=localIn.read(bytes))!=-1){
            netOut.write(bytes,0,len);
        }

        //5.传输完成,告知服务端传输完毕:socket.shutdownOutput()
        socket.shutdownOutput();
        System.out.println("上传文件结束");

        //6.获取网络的输入流,获取从服务端发送过来的数据
        InputStream netIn = socket.getInputStream();
            //接收一次对话不用while循环,一次读取就可以
        len = netIn.read(bytes);
        System.out.println(new String(bytes,0,len));

        //7.上传完毕,释放资源
        localIn.close();
        socket.close();
    }
}

优化:

问题:

​ 每次只能上传一张图片, 上传下一张要重新启动服务端和客户端

​ 如果多人上传,只能等上一位用户上传完成之后 再进行上传 , 效率低下

解决:

​ 使用线程进行同步操作 , 且用线程池

优化的服务端:

package com.test.test03;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ServerBetter {
    public static void main(String[] args) throws IOException {
        //创建线程池
        ExecutorService threadPool =
                Executors.newFixedThreadPool(10);//可以并发处理10个客户端

        //1.创建ServerSocket服务端对象,绑定端口
        ServerSocket serverSocket = new ServerSocket(8888);

        while (true) {
            //2.等待客户端连接
            System.out.println("等待客户端连接...");
            Socket socket = serverSocket.accept();
            System.out.println("客户端连接成功!");

            //创建任务,提交到线程池
            threadPool.submit(new FileUpload(socket));
        }
    }
}

//上传逻辑,线程任务类
class FileUpload implements Runnable{
    //需要用到Socket,设置成员变量
    private Socket socket;

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

    @Override
    public void run() {
        try{
            //3.获取网络输入流,接收客户端发送过来的文件数据
            InputStream netIn = socket.getInputStream();
            //4.创建本地的输出,用来保存接收到的文件数据到硬盘
            //上传多次图片,名字不能重复,否则会覆盖
            FileOutputStream localOut = new FileOutputStream("G:/Server/"+System.currentTimeMillis()+".jpg");

            //5.边读,边写,开始上传
            System.out.println("开始上传数据");
            byte[] bytes = new byte[1024];
            int len;
            while ((len=netIn.read(bytes))!=-1){//读取客户端发过来的文件
                localOut.write(bytes,0,len);//将数据写到硬盘中
            }
            System.out.println("上传结束");

            //6.获取网络的输出流,告诉客户端存储数据完毕
            OutputStream netOut = socket.getOutputStream();
            netOut.write("上传成功".getBytes());

            //7.释放资源
            localOut.close();
            socket.close();
//            serverSocket.close();要一直接收,服务端对象不关闭
        } catch (Exception e){
            System.out.println("上传失败:原因"+e.getMessage());
        }
    }
}

posted @ 2020-06-16 08:18  阿亮在努力  阅读(500)  评论(0)    收藏  举报