第三章、综合案例
3.1 文件上传案例
原理:客户端读取本地的文件,把文件上传到服务器,服务器把上传的文件保存到服务器的硬盘上
-
客户端使用本地的字节输入流,读取要上传的文件
-
客户端使用网络字节输出流,把读取到的文件上传到服务器
-
服务器使用网络字节输入流,读取客户端上传的文件
-
服务器使用本地的字节输出流,把读取到的文件保存到服务器的硬盘上
-
服务器使用网络字节输出流,给客户端回写一个“上传成功”
-
客户端使用网络字节输入流读取服务器回写的数据
-
释放资源
注意:
客户端和服务器和本地硬盘进行读写,需要使用自己创建的字节流对象(本地流)
客户端和服务器之间进行读写,必须使用Socket中提供的字节流对象(网络流)
文件上传的原理,就是文件的复制
明确:
数据源
数据目的地
文件上传优化
-
文件名称写死:创建文件使用不同名字
-
循环接受问题:始终开启Server,不断接受文件
-
效率问题:多线程解决
服务器代码:
/**
* 文件上传案例服务器:读取客户端上传的文件,保存到服务器的硬盘,给客户端回写"上传成功"
*/
public class TCPServer {
public static void main(String[] args) throws IOException {
//1、创建一个服务器ServerSocket对象,和系统要指定的端口号
ServerSocket server = new ServerSocket(8888);
//2、使用ServerSocket对象中的方法accept获取到请求的客户端Socket对象
/*
* 让服务器一直处于监听状态
*/
while (true){
Socket socket = server.accept();
/*
* 使用多线程,上传一次文件创建一个线程
*/
new Thread(new Runnable() {
@Override
public void run() {
try{
//3、使用Socket对象中的方法getInputSteam,获取到网络字节输入流InputSteam对象
InputStream is = socket.getInputStream();
//4、判断服务器硬盘上upload文件夹是否存在,不存在则创建
File file = new File("/Users/cwq/IdeaProjects/Net/src/upload");
if(!file.exists()){
file.mkdir();
}
//5、创建本地字节输出流对象FileOutputStream,构造方法中绑定要输出的目的地
/*
* 自定义命名规则:域名+毫秒值+随机数
jpg文件前需要加/
*/
//FileOutputStream fos = new FileOutputStream(file + "/1.jpg");
String filename = "cwq" + System.currentTimeMillis() + new Random().nextInt() + ".jpg";
FileOutputStream fos = new FileOutputStream(file + "/" + filename);
//6、使用网络字节输入流InputSteam的方法read读取客户端上传的文件
int len = 0;
byte[] bytes = new byte[1024];
while((len = is.read(bytes))!=-1){
//7、使用本地字节输出流对象中的方法write把读取到的文件保存到服务器的硬盘上
fos.write(bytes,0,len);
}
//8、使用Socket对象中的方法getOutputSteam,获取到网络字节输出流OutputSteam对象
//9、使用网络字节输出流OutputSteam对象的write方法给客户端回写"上传成功"
socket.getOutputStream().write("上传成功".getBytes());
//10、释放资源(FileOutputStream,Socket,ServerSocket)
fos.close();
socket.close();
}catch (IOException e){
System.out.println(e);
}
}
}).start();
}
//server.close();
}
}
客户端代码
/**
* 文件上传案例的客户端:读取本地文件,上传到服务器,读取服务器回写的数据
*/
public class TCPClient {
public static void main(String[] args) throws IOException {
//1、创建一个本地字节输入流FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("/Users/cwq/IdeaProjects/Net/src/image/1.jpg");
//2、创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
Socket socket = new Socket("127.0.0.1",8888);
//3、使用Socket中的方法getOutputStream,获取网络字节输出流OutputStream对象
OutputStream os = socket.getOutputStream();
//4、使用本地字节输入流FileInputStream对象中方法read,读取本地文件
int len = 0;
byte[] bytes = new byte[1024];
while ((len = fis.read(bytes))!=-1){
//5、使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器
os.write(bytes,0,len);
}
/**
* read方法读取不到-1。导致阻塞,while进入死循环
* 解决:上传完文件,给服务器一个结束标记
* void shutdownOutput() 禁止此套接字的输出流
* 对于TCP套接字,任何以前写入的数据都将被发送,并且后跟TCP的正常连接终止序列
*/
socket.shutdownOutput();
//6、使用Socket中的方法getInputStream,获取网络字节输入流InputStream对象
InputStream is = socket.getInputStream();
//7、使用网络字节输入流InputStream对象的方法read读取服务器回写的数据
while ((len = is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
//8、释放资源(FileInputStream,Socket)
fis.close();
socket.close();
}
}