您的位置:首页 > 理论基础 > 计算机网络

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

2015-01-09 13:46 225 查看
原文地址:http://blog.csdn.net/whoami021/article/details/21656875

上一篇文章我们实现聊天的功能,下面我们看文件传输怎么实现。
我的做法是:增加一个文件服务器,所有上传和下载文件的操作都由文件服务器来处理。
因此处理逻辑是这样的:如果用户请求上传文件或者下载文件,那么就将用户直接与文件服务器通信,而不用经过中央服务器。
所以现在的问题是知道java怎么实现上传和下载文件,如果这个问题解决了,那基本就搞定了。
首先,文件传输基本都是用面向连接的方式。因为无连接的方式容易丢包,一旦丢了一个数据包,文件就坏了,所有努力全白费。但是需要注意的是面向连接的方式,在服务器处理完一个连接后该连接就关闭了。
下面看代码,在原来的基础上我新建了两个主要文件:FileServer.java和FileClient..java。

[java] view plaincopy



package chat.net.file;  
  
import java.io.BufferedInputStream;  
import java.io.BufferedOutputStream;  
import java.io.DataInputStream;  
import java.io.DataOutputStream;  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.net.ServerSocket;  
import java.net.Socket;  
import java.util.Iterator;  
import java.util.Set;  
import java.util.TreeMap;  
  
import chat.Globals;  
  
/** 
 * 文件服务器 
 *  
 * @author michael 
 *  
 */  
public class FileServer {  
  
    private TreeMap<String, String> fileMap = new TreeMap<>();  
  
    private final String SavePath = "save/";// 上传文件保存目录  
  
    private final int port = 8821;  
  
    private ServerSocket ss;  
  
    private Socket s;  
  
    private String sender;// 上传者名字  
  
    private String receiver;// 接收者名字  
  
    private int bufferSize = 8192;  
  
    public void start() {  
        try {  
            // 创建目录  
            File file = new File(SavePath);  
            if (!file.exists()) {  
                file.mkdir();  
            }  
            ss = new ServerSocket(port);  
            while (true) {  
                s = ss.accept();  
                DataInputStream dis = new DataInputStream(  
                        new BufferedInputStream(s.getInputStream()));  
                dis.readByte();// 运行环境  
                int req = dis.readInt();  
                if (req == Globals.UploadReq) {// 用户上传文件  
                    recvFile(dis);  
                } else {// 用户下载文件  
                    sendFile(dis);  
                }  
            }  
        } catch (IOException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
    }  
  
    private void recvFile(DataInputStream dis) {  
        DataOutputStream dos = null;  
        try {  
            sender = dis.readUTF();// 发送者名字  
            String savePath = SavePath;  
            byte[] buf = new byte[bufferSize];  
            long len = 0;  
  
            String fileName = dis.readUTF();// 可能接收到终止的通知  
            if (fileName.equals(String.valueOf(Globals.Exit))) {  
                dis.close();  
                return;  
            }  
  
            savePath += fileName;  
            dos = new DataOutputStream(new BufferedOutputStream(  
                    new BufferedOutputStream(new FileOutputStream(savePath))));  
            len = dis.readLong();  
  
            System.out.println("文件的长度为:" + len);  
  
            while (true) {  
                int read = 0;  
                if (dis != null) {  
                    read = dis.read(buf);  
                }  
                if (read == -1) {  
                    break;  
                }  
                dos.write(buf, 0, read);  
            }  
            fileMap.put(fileName, sender);  
            System.out.println("接收完成,文件存为" + savePath);  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            try {  
                dis.close();  
                if (dos != null) {  
                    dos.close();  
                }  
            } catch (IOException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
        }  
    }  
  
    private void sendFile(DataInputStream dis) {  
        DataOutputStream dos = null;  
        DataInputStream fis = null;  
        try {  
            receiver = dis.readUTF();  
            dos = new DataOutputStream(s.getOutputStream());  
            // 给客户端发送文件列表  
            String fileList = "文件列表:\n";  
            if (fileMap.size() == 0) {  
                dos.writeUTF("");  
                return;  
            }  
            Set<String> set = fileMap.keySet();  
            Iterator<String> it = set.iterator();  
            String key;  
            int i = 0;  
            while (it.hasNext()) {  
                ++i;  
                key = it.next();  
                fileList += i + ".<" + key + "," + fileMap.get(key) + ">";  
            }  
            dos.writeUTF(fileList);  
            String fileName = getFileName(fileList, dis.readInt());  
            File file = new File(SavePath + fileName);  
            // 开始发送文件  
            fis = new DataInputStream(new BufferedInputStream(  
                    new FileInputStream(file)));  
            dos.writeUTF(fileName);  
            dos.flush();  
            dos.writeLong((long) file.length());  
            dos.flush();  
  
            byte[] buf = new byte[bufferSize];  
            int read = 0;  
  
            while (true) {  
                read = fis.read(buf);  
                if (read == -1) {  
                    break;  
                }  
                dos.write(buf, 0, read);  
            }  
            dos.flush();  
            System.out.println("文件" + fileName + "传输完成");  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
        } finally {  
            try {  
                dis.close();  
                if (fis != null) {  
                    fis.close();  
                }  
                dos.close();  
            } catch (IOException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
        }  
    }  
  
    private String getFileName(String fileList, int no) {  
        String fileName = fileList.substring(fileList.indexOf(String  
                .valueOf(no)));  
        fileName = fileName.substring(fileName.indexOf("<") + 1,  
                fileName.indexOf(","));  
        return fileName;  
    }  
  
    public static void main(String[] args) {  
        new FileServer().start();  
    }  
}  
[java] view plaincopy



package chat.net.file;  
  
import java.io.BufferedInputStream;  
import java.io.BufferedOutputStream;  
import java.io.DataInputStream;  
import java.io.DataOutputStream;  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.net.Socket;  
import java.net.UnknownHostException;  
import java.util.Scanner;  
  
import chat.Globals;  
  
/** 
 * 文件客户端 支持上传和下载文件 
 *  
 * @author michael 
 *  
 */  
public class FileClient {  
  
    private String HOST = "127.0.0.1";  
  
    private final int port = 8821;  
  
    private Socket socket;  
  
    private String ENV = "linux";// 运行环境  
  
    private int bufferSize = 8192;  
  
    private Scanner sc = new Scanner(System.in);  
  
    /** 
     * 上传文件 
     *  
     * @param req 
     * @param peer 
     */  
    public void uploadFile(int req, String peer) {  
        try {  
            socket = new Socket(HOST, port);  
            sendMessage(req, peer);// 发送操作类型  
            System.out.print("输入上传文件的绝对路径:");  
            String path = sc.next();  
            // String path = "/home/michael/Desktop/zouning71.rar";  
  
            // 发送文件  
            File file = new File(path);  
            DataInputStream dis = new DataInputStream(new BufferedInputStream(  
                    new FileInputStream(file)));  
            DataOutputStream dos = new DataOutputStream(  
                    socket.getOutputStream());  
            if (!file.exists()) {  
                System.out.println("该文件不存在");  
                dos.writeUTF(String.valueOf(Globals.Exit));  
                dos.flush();  
                return;  
            }  
            sendFile(dis, dos, file);  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
        }  
    }  
  
    private void sendFile(DataInputStream dis, DataOutputStream dos, File file) {  
        try {  
            // 将文件名及长度发给服务器  
            dos.writeUTF(file.getName());  
            dos.flush();  
            dos.writeLong((long) file.length());  
            dos.flush();  
  
            byte[] buf = new byte[bufferSize];  
            int read = 0;  
  
            while (true) {  
                read = dis.read(buf);  
                if (read == -1) {  
                    break;  
                }  
                dos.write(buf, 0, read);  
            }  
            dos.flush();  
            // 注意关闭socket链接,不然客户端会等待server的数据过来,  
            // 直到socket超时,导致数据不完整。  
            dis.close();  
            dos.close();  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
        }  
    }  
  
    /** 
     * 下载文件 
     *  
     * @param req 
     * @param peer 
     */  
    public void downloadFile(int req, String peer) {  
        try {  
            socket = new Socket(HOST, port);  
            sendMessage(req, peer);// 发送操作类型  
            DataInputStream dis = new DataInputStream(socket.getInputStream());  
            DataOutputStream dos = new DataOutputStream(  
                    socket.getOutputStream());  
            // 接收文件列表  
            String fileList = dis.readUTF();  
            if (fileList.equals("")) {  
                System.out.println("服务器没有文件");  
                return;  
            }  
            System.out.println(fileList);  
            System.out.print("输入要下载的文件序号:");  
            dos.writeInt(sc.nextInt());  
            dos.flush();  
            System.out.print("输入文件的保存位置(绝对路径):");  
            String savePath = sc.next();  
            // String savePath = "/home/michael/Desktop/";  
            recvFile(dis, dos, savePath);  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
        }  
    }  
  
    private void sendMessage(int req, String peer) {  
        DataOutputStream dos = null;  
        try {  
            dos = new DataOutputStream(socket.getOutputStream());  
            if (ENV.equalsIgnoreCase("windows")) {  
                dos.writeByte(0x1);  
                dos.flush();  
            } else if (ENV.equalsIgnoreCase("unix")) {  
                dos.writeByte(0x2);  
                dos.flush();  
            } else if (ENV.equalsIgnoreCase("linux")) {  
                dos.write(0x3);  
                dos.flush();  
            } else {  
                dos.writeUTF(ENV);  
                dos.flush();  
            }  
            dos.writeInt(req);// 向服务器发送操作类型:上传文件OR下载文件  
            dos.writeUTF(peer);// 上传者或者下载者  
            dos.flush();  
        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
    }  
  
    private void recvFile(DataInputStream dis, DataOutputStream dos,  
            String savePath) {  
        try {  
            byte[] buf = new byte[bufferSize];  
            long len = 0;  
  
            String fileName = dis.readUTF();  
            if (!savePath.endsWith("/")) {  
                savePath += "/";  
            }  
            savePath += fileName;  
            dos = new DataOutputStream(new BufferedOutputStream(  
                    new BufferedOutputStream(new FileOutputStream(savePath))));  
            len = dis.readLong();  
  
            System.out.println("文件的长度为:" + len);  
  
            int read = 0;  
            while (true) {  
                read = dis.read(buf);  
                if (read == -1) {  
                    break;  
                }  
                dos.write(buf, 0, read);  
            }  
            System.out.println("接收完成,文件存为" + savePath);  
            dis.close();  
            dos.close();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
  
    public static void main(String[] args) {  
        FileClient client = new FileClient();  
        client.uploadFile(Globals.UploadReq, "noname");  
        client.downloadFile(Globals.DownloadReq, "noname");  
    }  
}  
上面这两个文件就可以实现文件上传和下载了,有需要完整工程代码的请点击这里。
测试的时候先运行两个服务器:Server和FileServer,然后在运行Main。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: