本来想写一个分布式文件系统,类似Hadoop,以此来增加Hadoop的认识,但是奈何技术受限,所以先写一个一对一的文件传输系统。

一、设计方向

设计一个简单的网盘,服务器一台,客户端若干。实现简单地文件传输。

二、设计思路

  1. 运用serversocketsocket网络编程作为底层来实现框架。
  2. 运用Java的I/O实现文件传输的一系列问题。
  3. 运用配置文件properties来实现统一的参数管理。

三、系统文件版本v0.20.8.2.1的问题以及以后改进

我给我写的这个简单的系统框架起了一个简单名字LeeFileSystem,显得有些仪式感,另外,给它整了一个版本号v0.20.8.2.1,更有仪式感,哈哈。

版本v0.20.8.2.1问题改进思路
  1. 传输的文件仅限文本文件。

改进:先学学序列化与反序列化,和如何传输一个压缩包之类的

  1. 再Java-12的jdk编写的代码,在服务端jdk-1.8.1竟然报错,显示版本不对。

改进:增加服务端的代码开发

  1. 框架鲁棒性差,耦合性较为满意

改进:开发日志功能,开发错误错误抓取功能,以便更好开发

四、代码及运行结果

基于hadoop 的网盘 基于hadoop网盘设计_socket


为了降低耦合性,我多写了几个类,以便管理和维护。

(1)第一段代码:socket连接

基于hadoop 的网盘 基于hadoop网盘设计_基于hadoop 的网盘_02

服务器端

package cn.ServerSocketTransform.connect;

import cn.ServerSocketTransform.transform.Commandaccess;
import cn.ServerSocketTransform.transform.FileInput;
import cn.ServerSocketTransform.transform.FileOutput;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 服务器端 ,此端在服务器端启动
 */

public class ConnectServer {

    private static  final int port = 8848;

    private ServerSocket serverSocket;
    private Socket socket;

    private Commandaccess commandaccess;
    private String[] command;


    /**
     * 开启服务器
     * @throws IOException
     */
    public ConnectServer() throws IOException {

        /**
         * 服务器开启
         */
        serverSocket = new ServerSocket(this.port);
        System.out.println("waiting connection...");

        /**
         * 循环服务
         */
        while(true){

            /**
             * 接受请求,并获得地址
             */
            socket = serverSocket.accept();
            System.out.println(serverSocket.getInetAddress() + ":connect successfully!");

            /**
             * 接受客户端发送的命令,并处理
             * 放入if-else当中
             * download下载,即服务端--data-->客户端
             * upload上传,即服务端<--data--客户端
             */
            commandaccess = new Commandaccess(socket);
            command = commandaccess.getcommand();

            /**
             * commands[0]:是下载或上传的命令
             * commands[1-2]:是下载的地址
             */
            if (command[0].equals("download")){

                new Thread(()->{

                    try {
                        FileOutput fo = new FileOutput(socket);
                        fo.send(command[1]);
                        fo.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }).start();

            }else if (command[0].equals("upload")){

                new Thread(()->{

                    try {
                        FileInput fi = new FileInput(socket);
                        fi.download(command[2]);//上传到服务器的地址
                        fi.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }).start();
            }else {

                System.out.println("Error Command");
            }
        }
    }

    public void close() throws IOException {

        serverSocket.close();
    }

    /**
     public static void main(String[] args) throws IOException {

        ConnectServer connectServer = new ConnectServer();

        connectServer.close();
    }*/

    public Socket getSocket() {
        return socket;
    }

    public void setSocket(Socket socket) {
        this.socket = socket;
    }
}

客户端

package cn.ServerSocketTransform.connect;

import cn.ServerSocketTransform.transform.Command;
import cn.ServerSocketTransform.transform.FileInput;
import cn.ServerSocketTransform.transform.FileOutput;

import java.io.IOException;
import java.net.Socket;

/**
 * 此端在客户端使用
 */

public class ConnectServerClien {

    private static final int ServerPort = 8848;

    private Socket socket;

    private Command command;
    private String[] commands;


    public ConnectServerClien(String ip) throws IOException {

        /**
         * 发送请求至服务器
         */
        socket = new Socket(ip, ServerPort);

        /**
         * 发送命令,并由if-else来执行解析
         * download下载,即服务端--data-->客户端
         * upload上传,即服务端<--data--客户端
         */
        command = new Command(socket);
        commands = command.commandsend();

        /**
         * commands[0]:是下载或上传的命令
         * commands[1-2]:是下载的地址
         */
        if (commands[0].equals("download") ){

            new Thread(()->{

                try {
                    FileInput fi = new FileInput(socket);
                    fi.download(commands[2]);
                    fi.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }else if (commands[0].equals("upload")){

            new Thread(()->{

                try {
                    FileOutput fo = new FileOutput(socket);
                    fo.send(commands[1]);
                    fo.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    public void close() throws IOException {

        socket.close();
    }

    /**
    public static void main(String[] args) throws IOException {

        ConnectServerClien connectServerClien = new ConnectServerClien("127.0.0.1");

        connectServerClien.close();
    }*/

    public Socket getSocket() {
        return socket;
    }

    public void setSocket(Socket socket) {
        this.socket = socket;
    }
}

(2)第二段代码:文件传输

因为考虑到要在服务器上运行,所以想写一个简单的命令运行方式,但好像,不是这么个设计方法。

考虑到用shell,我还是scanner来实例化我的伪命令吧。

基于hadoop 的网盘 基于hadoop网盘设计_网络_03


发送命令的客户端

package cn.ServerSocketTransform.transform;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

/**
 * 此代码适用于发送命令,与Linux的bin相当
 */

public class Command {

    private Socket socket;
    private OutputStream outputStream;

    public Command(Socket socket){

        this.socket = socket;

        System.out.println("命令:\n" +
                "download serveraddress\\file localaddress\\file\n" +
                "upload localaddress\\file serveraddress\\file\n" +
                "---------------------------------");

        System.out.println("[LFS@clience]");
    }

    public String[] commandsend() throws IOException {

        /**
         * 键盘输入流
         */
        Scanner scanner = new Scanner(System.in);
        String command = scanner.nextLine();

        /**
         * 发送至服务器端
         */
        outputStream = socket.getOutputStream();
        outputStream.write(command.getBytes());

        /**
         * 本地解析
         */
        String[] commands = command.split(" ");

        /*for (String i : commands){
            System.out.println(i);
        }*/

        /*for (int i = 0; i< 3 ; i++){

            if (commands[i].equals("download")) {
                System.out.println(commands[i] + i);
            }

        }*/
        return  commands;
    }


}

接受命令的服务端

package cn.ServerSocketTransform.transform;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

/**
 * 此代码适用于接受命令,与Linux的bin相当
 */

public class Commandaccess {

    private Socket socket;
    private InputStream inputStream;

    public Commandaccess(Socket socket){

        this.socket = socket;
    }

    public String[] getcommand() throws IOException {

        /**
         * 接受命令,并解析
         */
        inputStream = socket.getInputStream();
        byte[] b = new byte[1024];
        int len = inputStream.read(b);
        String command = new String(b ,0 ,len);

        /**
         * 返回服务器
         */
        String[] commands = command.split(" ");

        return commands;
    }
}

文件传输发送端

package cn.ServerSocketTransform.transform;

import java.io.*;
import java.net.Socket;

/**
 * 用来 上传 文件
 */

public class FileOutput {

    private Socket socket;

    private BufferedInputStream bis;
    private BufferedOutputStream bos;

    /**
     * 传入socket对象
     * @param socket
     * @throws IOException
     */
    public FileOutput(Socket socket) throws IOException {

        this.socket = socket;
    }

    /**
     * 传入指定的发送的文件路径
     * @param path
     * @throws IOException
     */
    public void send(String path) throws IOException {

        bis = new BufferedInputStream(new FileInputStream(path));//指定的文件下载路径
        bos = new BufferedOutputStream(socket.getOutputStream());

        byte[] b = new byte[1024 * 8];
        int len;
        while ((len = bis.read(b)) != -1){

            bos.write(b, 0, len);
            bos.flush();
        }

        System.out.println("sending mission success");
    }

    public void close() throws IOException {

        bis.close();
        bos.close();
    }
}

文件传送接收端

package cn.ServerSocketTransform.transform;

import java.io.*;
import java.net.Socket;

/**
 *  下载
 *  /root/Transform
 */

public class FileInput {

    private Socket socket;

    private BufferedInputStream bis;
    private BufferedOutputStream bos;

    /**
     * 获取socket对象,进行文件下载
     * @param socket
     * @throws IOException
     */
    public FileInput(Socket socket) throws IOException {

        this.socket = socket;
    }

    /**
     * 传入服务器文件的地址,或者下载文件的地址
     * @param path
     * @throws IOException
     */
    public void download(String path) throws IOException {

        bis = new BufferedInputStream(socket.getInputStream());
        bos = new BufferedOutputStream(new FileOutputStream(path));//path是指定的下载地址

        byte[] b = new byte[1024 * 8];
        int len;
        while ((len = bis.read(b)) != -1){

            bos.write(b, 0, len);
        }

        System.out.println("downloading mission success");
    }

    public void close() throws IOException {

        bis.close();
        bos.close();
    }
}

(3)第三段代码:配置文件、初始化文件夹

基于hadoop 的网盘 基于hadoop网盘设计_socket_04


基于hadoop 的网盘 基于hadoop网盘设计_socket_05


配置文件

#该文件系统名称LeeFileSystem,简称LFS网络文件系统
#当前Version:0.20.8.2.1-inner
#核心技术为File与socket网络编程,将来加入分布式
#受启发于Hadoop,给文件系统耦合度低,高效率

#配置服务器的IP与文件系统的根目录
ServerAddress=D:\\JavaProgramSummarySite\\ServerSocketTransform\\test
ServerIP=127.0.0.1

加载配置文件

package cn.FileSystem;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

/**
 * 加载类,加载配置文件
 */
public class PropertiesUtil {

    private Properties properties;
    private File file;
    private FileInputStream fileInputStream;

    /**
     * 读取加载文件位置,以此加载配置
     * @throws IOException
     */
    public  PropertiesUtil() throws IOException {

        properties = new Properties();
        file = new File("ServerAddress.properties");
        fileInputStream = new FileInputStream(file.getAbsolutePath());
        properties.load(fileInputStream);
    }

    /**
     * 返回加载类对象,以便获取加载的文件信息
     * @return
     */
    public Properties getProperties() {
        return properties;
    }
}

将配置文件加载后,即可读取并传入其他文件,配置文件的内容是即将创建的实现文件传输保存地址的文件,还有服务器端的IP这样,客户端只需读取服务器的IP即可实现在预先创建的文件夹下的文件操作。当然,服务端也可以通过读取配置文件里面的那个地址,来实现,这个“网盘”的存储地址。

初始化文件

package cn.FileSystem;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 创建Lee文件系统的地址
 */
public class CreateFileBlock {

    private PropertiesUtil propertiesUtil;
    private String address;
    private File file;
    private Date date;

    private static final String addr = "SERVER";

    /**
     * 先加载配置文件
     * 获取要创建文件的地址
     * 判断文件存在与否,输出文件信息
     * @throws IOException
     */
    public CreateFileBlock() throws IOException {

        propertiesUtil = new PropertiesUtil();
        address = propertiesUtil.getProperties().getProperty("ServerAddress");

        file = new File(address+"\\"+addr);

        if (file.exists()){

            date = new Date(file.lastModified());
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            String time = format.format(date);

            System.out.println("Absolutepath:" + file.getAbsolutePath()
                    +"\nlastmodified:" + time );
        }else {

            System.out.println("Create successfully:" + file.mkdirs()
                    +"\nisDirectory:" + file.isDirectory()
                    +"\nAbsolutepath:" + file.getAbsolutePath()
                    +"\nKB:" + file.length() );
        }
    }
}

(4)总主函数

服务端

package cn.ServerSocketTransform.job;

import cn.FileSystem.CreateFileBlock;
import cn.ServerSocketTransform.connect.ConnectServer;


import java.io.IOException;

public class jobserver {

    public static void main(String[] args) throws IOException, InterruptedException {

        /**
         * 此对象是用来创建工作区域的
         */
        CreateFileBlock createFileBlock = new CreateFileBlock();

        ConnectServer connectServer = new ConnectServer();

        Thread.sleep(5000);

        connectServer.close();
    }
}

客户端

package cn.ServerSocketTransform.job;

import cn.FileSystem.PropertiesUtil;
import cn.ServerSocketTransform.connect.ConnectServerClien;


import java.io.IOException;

public class jobclien {

    public static void main(String[] args) throws IOException, InterruptedException {

        PropertiesUtil propertiesUtil = new PropertiesUtil();

        ConnectServerClien connectServerClien = new ConnectServerClien(propertiesUtil.getProperties().getProperty("ServerIP"));

        Thread.sleep(5000);

        connectServerClien.close();
    }
}

五、运行

开服务器、开客户端:

基于hadoop 的网盘 基于hadoop网盘设计_System_06


基于hadoop 的网盘 基于hadoop网盘设计_网络_07

可以看到创建的SERVER文件夹,和客户端连接的信息

发送消息:

基于hadoop 的网盘 基于hadoop网盘设计_java_08


基于hadoop 的网盘 基于hadoop网盘设计_socket_09


上图可见,在server中,有一个已经被传送来的文件。

简单功能实现,以后再去完善。