C/S+P2P网络模型(二)--上传&下载文件

原文地址:http://blog.csdn.net/whoami021/article/details/21656875

 
 

上一篇文章我们实现聊天的功能,下面我们看文件传输怎么实现。

我的做法是:增加一个文件服务器,所有上传和下载文件的操作都由文件服务器来处理。

因此处理逻辑是这样的:如果用户请求上传文件或者下载文件,那么就将用户直接与文件服务器通信,而不用经过中央服务器。

所以现在的问题是知道java怎么实现上传和下载文件,如果这个问题解决了,那基本就搞定了。

首先,文件传输基本都是用面向连接的方式因为无连接的方式容易丢包,一旦丢了一个数据包,文件就坏了,所有努力全白费。但是需要注意的是面向连接的方式,在服务器处理完一个连接后该连接就关闭了。

下面看代码,在原来的基础上我新建了两个主要文件:FileServer.javaFileClient..java。

[java] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package chat.net.file;  
  2.   
  3. import java.io.BufferedInputStream;  
  4. import java.io.BufferedOutputStream;  
  5. import java.io.DataInputStream;  
  6. import java.io.DataOutputStream;  
  7. import java.io.File;  
  8. import java.io.FileInputStream;  
  9. import java.io.FileOutputStream;  
  10. import java.io.IOException;  
  11. import java.net.ServerSocket;  
  12. import java.net.Socket;  
  13. import java.util.Iterator;  
  14. import java.util.Set;  
  15. import java.util.TreeMap;  
  16.   
  17. import chat.Globals;  
  18.   
  19. /** 
  20.  * 文件服务器 
  21.  *  
  22.  * @author michael 
  23.  *  
  24.  */  
  25. public class FileServer {  
  26.   
  27.     private TreeMap<String, String> fileMap = new TreeMap<>();  
  28.   
  29.     private final String SavePath = "save/";// 上传文件保存目录  
  30.   
  31.     private final int port = 8821;  
  32.   
  33.     private ServerSocket ss;  
  34.   
  35.     private Socket s;  
  36.   
  37.     private String sender;// 上传者名字  
  38.   
  39.     private String receiver;// 接收者名字  
  40.   
  41.     private int bufferSize = 8192;  
  42.   
  43.     public void start() {  
  44.         try {  
  45.             // 创建目录  
  46.             File file = new File(SavePath);  
  47.             if (!file.exists()) {  
  48.                 file.mkdir();  
  49.             }  
  50.             ss = new ServerSocket(port);  
  51.             while (true) {  
  52.                 s = ss.accept();  
  53.                 DataInputStream dis = new DataInputStream(  
  54.                         new BufferedInputStream(s.getInputStream()));  
  55.                 dis.readByte();// 运行环境  
  56.                 int req = dis.readInt();  
  57.                 if (req == Globals.UploadReq) {// 用户上传文件  
  58.                     recvFile(dis);  
  59.                 } else {// 用户下载文件  
  60.                     sendFile(dis);  
  61.                 }  
  62.             }  
  63.         } catch (IOException e) {  
  64.             // TODO Auto-generated catch block  
  65.             e.printStackTrace();  
  66.         }  
  67.     }  
  68.   
  69.     private void recvFile(DataInputStream dis) {  
  70.         DataOutputStream dos = null;  
  71.         try {  
  72.             sender = dis.readUTF();// 发送者名字  
  73.             String savePath = SavePath;  
  74.             byte[] buf = new byte[bufferSize];  
  75.             long len = 0;  
  76.   
  77.             String fileName = dis.readUTF();// 可能接收到终止的通知  
  78.             if (fileName.equals(String.valueOf(Globals.Exit))) {  
  79.                 dis.close();  
  80.                 return;  
  81.             }  
  82.   
  83.             savePath += fileName;  
  84.             dos = new DataOutputStream(new BufferedOutputStream(  
  85.                     new BufferedOutputStream(new FileOutputStream(savePath))));  
  86.             len = dis.readLong();  
  87.   
  88.             System.out.println("文件的长度为:" + len);  
  89.   
  90.             while (true) {  
  91.                 int read = 0;  
  92.                 if (dis != null) {  
  93.                     read = dis.read(buf);  
  94.                 }  
  95.                 if (read == -1) {  
  96.                     break;  
  97.                 }  
  98.                 dos.write(buf, 0, read);  
  99.             }  
  100.             fileMap.put(fileName, sender);  
  101.             System.out.println("接收完成,文件存为" + savePath);  
  102.         } catch (Exception e) {  
  103.             e.printStackTrace();  
  104.         } finally {  
  105.             try {  
  106.                 dis.close();  
  107.                 if (dos != null) {  
  108.                     dos.close();  
  109.                 }  
  110.             } catch (IOException e) {  
  111.                 // TODO Auto-generated catch block  
  112.                 e.printStackTrace();  
  113.             }  
  114.         }  
  115.     }  
  116.   
  117.     private void sendFile(DataInputStream dis) {  
  118.         DataOutputStream dos = null;  
  119.         DataInputStream fis = null;  
  120.         try {  
  121.             receiver = dis.readUTF();  
  122.             dos = new DataOutputStream(s.getOutputStream());  
  123.             // 给客户端发送文件列表  
  124.             String fileList = "文件列表:\n";  
  125.             if (fileMap.size() == 0) {  
  126.                 dos.writeUTF("");  
  127.                 return;  
  128.             }  
  129.             Set<String> set = fileMap.keySet();  
  130.             Iterator<String> it = set.iterator();  
  131.             String key;  
  132.             int i = 0;  
  133.             while (it.hasNext()) {  
  134.                 ++i;  
  135.                 key = it.next();  
  136.                 fileList += i + ".<" + key + "," + fileMap.get(key) + ">";  
  137.             }  
  138.             dos.writeUTF(fileList);  
  139.             String fileName = getFileName(fileList, dis.readInt());  
  140.             File file = new File(SavePath + fileName);  
  141.             // 开始发送文件  
  142.             fis = new DataInputStream(new BufferedInputStream(  
  143.                     new FileInputStream(file)));  
  144.             dos.writeUTF(fileName);  
  145.             dos.flush();  
  146.             dos.writeLong((long) file.length());  
  147.             dos.flush();  
  148.   
  149.             byte[] buf = new byte[bufferSize];  
  150.             int read = 0;  
  151.   
  152.             while (true) {  
  153.                 read = fis.read(buf);  
  154.                 if (read == -1) {  
  155.                     break;  
  156.                 }  
  157.                 dos.write(buf, 0, read);  
  158.             }  
  159.             dos.flush();  
  160.             System.out.println("文件" + fileName + "传输完成");  
  161.         } catch (Exception e) {  
  162.             // TODO: handle exception  
  163.             e.printStackTrace();  
  164.         } finally {  
  165.             try {  
  166.                 dis.close();  
  167.                 if (fis != null) {  
  168.                     fis.close();  
  169.                 }  
  170.                 dos.close();  
  171.             } catch (IOException e) {  
  172.                 // TODO Auto-generated catch block  
  173.                 e.printStackTrace();  
  174.             }  
  175.         }  
  176.     }  
  177.   
  178.     private String getFileName(String fileList, int no) {  
  179.         String fileName = fileList.substring(fileList.indexOf(String  
  180.                 .valueOf(no)));  
  181.         fileName = fileName.substring(fileName.indexOf("<") + 1,  
  182.                 fileName.indexOf(","));  
  183.         return fileName;  
  184.     }  
  185.   
  186.     public static void main(String[] args) {  
  187.         new FileServer().start();  
  188.     }  
  189. }  
[java] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package chat.net.file;  
  2.   
  3. import java.io.BufferedInputStream;  
  4. import java.io.BufferedOutputStream;  
  5. import java.io.DataInputStream;  
  6. import java.io.DataOutputStream;  
  7. import java.io.File;  
  8. import java.io.FileInputStream;  
  9. import java.io.FileOutputStream;  
  10. import java.io.IOException;  
  11. import java.net.Socket;  
  12. import java.net.UnknownHostException;  
  13. import java.util.Scanner;  
  14.   
  15. import chat.Globals;  
  16.   
  17. /** 
  18.  * 文件客户端 支持上传和下载文件 
  19.  *  
  20.  * @author michael 
  21.  *  
  22.  */  
  23. public class FileClient {  
  24.   
  25.     private String HOST = "127.0.0.1";  
  26.   
  27.     private final int port = 8821;  
  28.   
  29.     private Socket socket;  
  30.   
  31.     private String ENV = "linux";// 运行环境  
  32.   
  33.     private int bufferSize = 8192;  
  34.   
  35.     private Scanner sc = new Scanner(System.in);  
  36.   
  37.     /** 
  38.      * 上传文件 
  39.      *  
  40.      * @param req 
  41.      * @param peer 
  42.      */  
  43.     public void uploadFile(int req, String peer) {  
  44.         try {  
  45.             socket = new Socket(HOST, port);  
  46.             sendMessage(req, peer);// 发送操作类型  
  47.             System.out.print("输入上传文件的绝对路径:");  
  48.             String path = sc.next();  
  49.             // String path = "/home/michael/Desktop/zouning71.rar";  
  50.   
  51.             // 发送文件  
  52.             File file = new File(path);  
  53.             DataInputStream dis = new DataInputStream(new BufferedInputStream(  
  54.                     new FileInputStream(file)));  
  55.             DataOutputStream dos = new DataOutputStream(  
  56.                     socket.getOutputStream());  
  57.             if (!file.exists()) {  
  58.                 System.out.println("该文件不存在");  
  59.                 dos.writeUTF(String.valueOf(Globals.Exit));  
  60.                 dos.flush();  
  61.                 return;  
  62.             }  
  63.             sendFile(dis, dos, file);  
  64.         } catch (Exception e) {  
  65.             // TODO: handle exception  
  66.             e.printStackTrace();  
  67.         }  
  68.     }  
  69.   
  70.     private void sendFile(DataInputStream dis, DataOutputStream dos, File file) {  
  71.         try {  
  72.             // 将文件名及长度发给服务器  
  73.             dos.writeUTF(file.getName());  
  74.             dos.flush();  
  75.             dos.writeLong((long) file.length());  
  76.             dos.flush();  
  77.   
  78.             byte[] buf = new byte[bufferSize];  
  79.             int read = 0;  
  80.   
  81.             while (true) {  
  82.                 read = dis.read(buf);  
  83.                 if (read == -1) {  
  84.                     break;  
  85.                 }  
  86.                 dos.write(buf, 0, read);  
  87.             }  
  88.             dos.flush();  
  89.             // 注意关闭socket链接,不然客户端会等待server的数据过来,  
  90.             // 直到socket超时,导致数据不完整。  
  91.             dis.close();  
  92.             dos.close();  
  93.         } catch (Exception e) {  
  94.             // TODO: handle exception  
  95.             e.printStackTrace();  
  96.         }  
  97.     }  
  98.   
  99.     /** 
  100.      * 下载文件 
  101.      *  
  102.      * @param req 
  103.      * @param peer 
  104.      */  
  105.     public void downloadFile(int req, String peer) {  
  106.         try {  
  107.             socket = new Socket(HOST, port);  
  108.             sendMessage(req, peer);// 发送操作类型  
  109.             DataInputStream dis = new DataInputStream(socket.getInputStream());  
  110.             DataOutputStream dos = new DataOutputStream(  
  111.                     socket.getOutputStream());  
  112.             // 接收文件列表  
  113.             String fileList = dis.readUTF();  
  114.             if (fileList.equals("")) {  
  115.                 System.out.println("服务器没有文件");  
  116.                 return;  
  117.             }  
  118.             System.out.println(fileList);  
  119.             System.out.print("输入要下载的文件序号:");  
  120.             dos.writeInt(sc.nextInt());  
  121.             dos.flush();  
  122.             System.out.print("输入文件的保存位置(绝对路径):");  
  123.             String savePath = sc.next();  
  124.             // String savePath = "/home/michael/Desktop/";  
  125.             recvFile(dis, dos, savePath);  
  126.         } catch (Exception e) {  
  127.             // TODO: handle exception  
  128.             e.printStackTrace();  
  129.         }  
  130.     }  
  131.   
  132.     private void sendMessage(int req, String peer) {  
  133.         DataOutputStream dos = null;  
  134.         try {  
  135.             dos = new DataOutputStream(socket.getOutputStream());  
  136.             if (ENV.equalsIgnoreCase("windows")) {  
  137.                 dos.writeByte(0x1);  
  138.                 dos.flush();  
  139.             } else if (ENV.equalsIgnoreCase("unix")) {  
  140.                 dos.writeByte(0x2);  
  141.                 dos.flush();  
  142.             } else if (ENV.equalsIgnoreCase("linux")) {  
  143.                 dos.write(0x3);  
  144.                 dos.flush();  
  145.             } else {  
  146.                 dos.writeUTF(ENV);  
  147.                 dos.flush();  
  148.             }  
  149.             dos.writeInt(req);// 向服务器发送操作类型:上传文件OR下载文件  
  150.             dos.writeUTF(peer);// 上传者或者下载者  
  151.             dos.flush();  
  152.         } catch (Exception e) {  
  153.             // TODO Auto-generated catch block  
  154.             e.printStackTrace();  
  155.         }  
  156.     }  
  157.   
  158.     private void recvFile(DataInputStream dis, DataOutputStream dos,  
  159.             String savePath) {  
  160.         try {  
  161.             byte[] buf = new byte[bufferSize];  
  162.             long len = 0;  
  163.   
  164.             String fileName = dis.readUTF();  
  165.             if (!savePath.endsWith("/")) {  
  166.                 savePath += "/";  
  167.             }  
  168.             savePath += fileName;  
  169.             dos = new DataOutputStream(new BufferedOutputStream(  
  170.                     new BufferedOutputStream(new FileOutputStream(savePath))));  
  171.             len = dis.readLong();  
  172.   
  173.             System.out.println("文件的长度为:" + len);  
  174.   
  175.             int read = 0;  
  176.             while (true) {  
  177.                 read = dis.read(buf);  
  178.                 if (read == -1) {  
  179.                     break;  
  180.                 }  
  181.                 dos.write(buf, 0, read);  
  182.             }  
  183.             System.out.println("接收完成,文件存为" + savePath);  
  184.             dis.close();  
  185.             dos.close();  
  186.         } catch (Exception e) {  
  187.             e.printStackTrace();  
  188.         }  
  189.     }  
  190.   
  191.     public static void main(String[] args) {  
  192.         FileClient client = new FileClient();  
  193.         client.uploadFile(Globals.UploadReq, "noname");  
  194.         client.downloadFile(Globals.DownloadReq, "noname");  
  195.     }  
  196. }  

上面这两个文件就可以实现文件上传和下载了,有需要完整工程代码的请点击这里

测试的时候先运行两个服务器:Server和FileServer,然后在运行Main。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值