文件上传及线程优化
文件上传分析图解
\1. 【客户端】输入流,从硬盘读取文件数据到程序中。
\2. 【客户端】输出流,写出文件数据到服务端。
\3. 【服务端】输入流,读取文件数据到服务端程序。
\4. 【服务端】输出流,写出文件数据到服务器硬盘中。
\5. 【服务端】获取输出流,回写数据。
\6. 【客户端】获取输入流,解析回写数据。
服务器端实现:(优化之前)
步骤分析:
- 创建ServerSocket服务端对象,绑定端口
- 等待客户端连接:accept
- 获取网络输入流,接收客户端发送过来的文件数据:getInputStream
- 创建本地的输出,用来保存接收到的文件数据到硬盘中
- 边读,边写
- 获取网络输出流,告诉客户端发送数据完毕
- 释放资源
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();
}
}
客户端实现:
步骤分析:
- 先创建客户端Socket对象指定服务器端的ip和端口
- 获取本地的输入流,关联要上传的文件
- 获取网络的输出流,发送文件数据到服务端
- 边读,边写
- 当传输完成,要告诉服务端数据传输完毕:socket.shutdownOutput();
- 获取网络的输入流,获取服务端发送的数据
- 上传完成,释放资源
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());
}
}
}
唯有努力,人生没有白走的路,每一步都算数