利用多线程技术实现多用户可同时上传和下载文件

最近学习了多线程和网络编程中的C/S结构,便把这些知识结合在一起写了这个包含将本地文件上传到服务器端,和从服务器端下载文件保存到本地的案例,想和大家一起交流一下。

涉及内容:File、Socket、ServerSocket、Thread、InputStream、OutputStream等相关知识。

设计亮点:

1.文件名称写死的问题
服务端/客户端,保存文件的名称如果写死,那么最终导致服务器硬盘,只会保留一个文件,所以使用系统时间+文件后缀命名,保证文件名称唯一。

2.循环接收的问题
服务端,只保存一个文件就关闭了,之后的用户无法再上传,这是不符合实际的,使用循环改进,可以不断的接收不同用户的文件。

3.效率问题
服务端,在接收大文件时,可能耗费几秒钟的时间,此时不能接收其他用户上传,所以,使用多线程技术优化。

设计细节及源码:

文件上传:

文件上传分析图解
1. 【客户端】输入流,从硬盘读取文件数据到程序中。
2. 【客户端】输出流,写出文件数据到服务端。
3. 【服务端】输入流,读取文件数据到服务端程序。
4. 【服务端】输出流,写出文件数据到服务器硬盘中。

信息回写分析图解
前四步与基本文件上传一致.
5. 【服务端】获取输出流,回写数据。
6. 【客户端】获取输入流,解析回写数据。

文件下载原理与文件上传刚好相反,这里便不再赘述,直接奉上源码:

客户端:

 1 package cn.homeWork01.demo09C_S;
 2 
 3 // 客户端
 4 // 文件上传下载综合案例
 5 // 本程序操作对象为.txt结尾的文档,可自行修改相应的文档后缀命
 6 // 存在问题:不能连续向服务器写入数据
 7 import java.io.*;
 8 import java.net.Socket;
 9 
10 public class Client {
11     public static void main(String[] args) throws IOException{
12 
13         // 调用上传方法
14         // 此处为上传文件的路径和文件名
15         uploadClient("F:\\Test\\chushibiao.txt");
16         // 调用下载方法
17         downloadClient();
18     }
19 
20     // 文件上传
21     public static void uploadClient(String path) throws IOException {
22         Socket socket = new Socket("127.0.0.1",8888);
23         OutputStream os = socket.getOutputStream();
24         InputStream is = socket.getInputStream();
25         FileInputStream fis = new FileInputStream(path);
26 
27         // 向服务器发送文件
28         int len = 0;
29         byte[] bytes = new byte[1024];
30         while((len=fis.read(bytes))!=-1){
31             os.write(bytes,0,len);
32         }
33         //禁用此套接字的输出流(给服务器写一个结束标记)
34         socket.shutdownOutput();
35 
36         // 读取服务器的反馈信息
37         while ((len=is.read(bytes))!=-1) {
38             System.out.println(new String(bytes,0,len));
39         }
40 
41         // 关闭流和客户端
42         fis.close();
43         socket.close();
44 
45     }
46 
47     // 文件下载
48     public static void downloadClient() throws IOException{
49         Socket socket = new Socket("127.0.0.1",8889);
50         OutputStream os = socket.getOutputStream();
51         InputStream is = socket.getInputStream();
52 
53         // 判断文件夹是否存在
54         // 下载的文件保存到此目录下
55         File download = new File("F:\\Test\\download");
56         if(!download.exists()){
57             download.mkdirs();
58         }
59 
60         // 生成随机文件名
61         String downname = "\\"+System.currentTimeMillis()+".txt";
62         FileOutputStream fos = new FileOutputStream(download+downname);
63 
64         // 读取服务器发送的文件并写入本地
65         int len = 0;
66         byte[] bytes = new byte[1024];
67         while((len=is.read(bytes))!=-1){
68             fos.write(bytes,0,len);
69         }
70 
71         // 向服务器反馈接收成功信息
72         os.write("接收成功".getBytes());
73 
74         // 关闭流和客户端
75         fos.close();
76         socket.close();
77     }
78 }

服务器端:

  1 package cn.homeWork01.demo09C_S;
  2 
  3 // 文件上传下载服务器端
  4 
  5 import java.io.*;
  6 import java.net.ServerSocket;
  7 import java.net.Socket;
  8 
  9 public class Server {
 10     public static void main(String[] args) throws IOException {
 11 
 12         // 开启上传服务器
 13         uploadServer();
 14         // 开启下载服务器
 15         downloadServer();
 16     }
 17 
 18     // 文件上传服务器
 19     public static void uploadServer() throws IOException{
 20         ServerSocket serverSocket = new ServerSocket(8888);
 21         while(true){
 22             Socket socket = serverSocket.accept();
 23             new Thread(new Runnable() {
 24                 @Override
 25                 public void run() {
 26                     FileOutputStream fos = null;
 27                     try{
 28                         InputStream is = socket.getInputStream();
 29                         OutputStream os = socket.getOutputStream();
 30 
 31                         // 判断文件夹是否存在
 32                         // 此文件夹为上传至服务器的文件夹
 33                         File upload = new File("f:\\Server\\upload");
 34                         if(!upload.exists()){
 35                             upload.mkdirs();
 36                         }
 37 
 38                         // 生成随机文件名
 39                         String name = "\\"+System.currentTimeMillis()+".txt";
 40                          fos = new FileOutputStream(upload+name);
 41 
 42                         // 读取上传文件
 43                         int len = 0;
 44                         byte[] bytes = new byte[1024];
 45                         while((len = is.read(bytes))!=-1){
 46                             fos.write(bytes,0,len);
 47                         }
 48 
 49                         // 向客户端反馈信息
 50                         os.write("上传成功".getBytes());
 51                     }catch(Exception e){
 52                         e.printStackTrace();
 53                     }finally {
 54                         try {
 55                             fos.close();
 56                         } catch (IOException e) {
 57                             e.printStackTrace();
 58                         }
 59 
 60                         try {
 61                             socket.close();
 62                         } catch (IOException e) {
 63                             e.printStackTrace();
 64                         }
 65                     }
 66                 }
 67             }).start();
 68         }
 69     }
 70 
 71     // 文件下载服务器
 72     public static void downloadServer() throws IOException{
 73         ServerSocket serverSocket = new ServerSocket(8889);
 74         while (true){
 75             Socket socket = serverSocket.accept();
 76             new Thread(new Runnable() {
 77                 FileInputStream fis = null;
 78                 @Override
 79                 public void run() {
 80                     try{
 81                         InputStream is = socket.getInputStream();
 82                         OutputStream os = socket.getOutputStream();
 83 
 84 
 85                         // 创建下载文件路径
 86                         // 此路径为服务器端的下载文件夹及文件名
 87                         File pathname = new File("F:\\Server\\download\\b.txt");
 88                         fis = new FileInputStream(pathname);
 89 
 90                         // 将文件发送给客户端
 91                         int len=0;
 92                         byte[] bytes = new byte[1024];
 93                         while((len=fis.read(bytes))!=-1){
 94                             os.write(bytes,0,len);
 95                         }
 96                         // 禁用此套接字输出流
 97                         socket.shutdownOutput();
 98 
 99                         // 接收客户端的反馈信息
100                         while((len=is.read(bytes))!=-1){
101                             System.out.println(new String(bytes,0,len));
102                         }
103 
104                     }catch (Exception e){
105                         e.printStackTrace();
106                     }finally {
107                         try {
108                             socket.close();
109                         } catch (IOException e) {
110                             e.printStackTrace();
111                         }
112 
113                         try {
114                             fis.close();
115                         } catch (IOException e) {
116                             e.printStackTrace();
117                         }
118                     }
119                 }
120             }).start();
121         }
122     }
123 }

 

注意:

1.请先启动服务器端,再启动客户端!

2.本案例还未实现客户端与服务器端的连续通信,所以不能在下载程序的客户端传递想要下载的文件名称!

3.请单独使用上传程序或下载程序,否则会抛出异常!

4.服务器端须手动关闭,不然一直处于运行状态!

不足之处:

1.尚未实现客户端和服务器端的连续通信。

2.不能同时使用上传和下载程序。

3.还未设计友好的交互界面,普通人可能无法使用。

4.没有对线程数量进行限制,当开启过多线程,将会导致内存溢出异常(当然本程序还很难满足此项,大家可放心使用!)。

 

本案例还有很多不足之处,希望大家能够及时纠正。当然更希望能够对您有用!

posted @ 2020-09-08 21:28  令狐公子♥  阅读(1582)  评论(0)    收藏  举报