windows之间分发文件

背景

性能测试,使用分布式压力机进行规模较大的压测时,环境准备阶段需要将测试依赖的文件(测试数据文件、依赖jar包、依赖第三方程序等)拷贝到各个机器上
分布式压力机使用的是linux系统或或者是windows再或者是两者混用

linux机器之间cp文件有很多种,而且都很方便,不需要额外装软件,预装的就能实现文件拷贝比如scp、ftp等都能实现
windows之间就比较麻烦了,os中可能都没有启用ftp,也没有开足够的共享权限等。也有可能你完全配置好一台windows,制作模版,再装其他机器。(别抬杠,不排除这种方法)

使用ftp共享实现

不是我要介绍的重点,自己问问度娘,网上很大篇幅是介绍这种方式的(略)

文件中转实现分发

我倾向拿来主义,所以我借助第三的程序。废话少说来干的

准备

服务器准备

准备一台linux服务器:hostLinux
准备N台windows服务:hostWin1……hostWinN

软件准备

pscp和psexec
用法见附录或者去官网

需求

将hostWin1上的文件cp到hostWin2……hostWinN

实现

pscp能进行win与linux之间cp文件类似linux下的scp;
psexec可以在windows之间远程执行命令,更重要的是有一个-c参数,可以将执行的命令拷贝到远程机器上执行,这样要拷贝文件的机器就不需要提前将命令准备好(在这里是pscp命令,也就是hostWin2……hostWinN上不需要做任何准备)

检查linux和个windows之间的ping,windows之间的ping

连通性检查可选,最好还是检查一下

将待分发的文件上传至hostLinux上的指定目录

pscp -pw hostLinuxPasswd [-r] localFile root@hostLinux:/root/transFile/

在hostWin1上控制在hostWin2……hostWinN上执行pscp命令

psexec -u hostWin2user -p hostWin2passwd -c -f pscp -pw xxxxx [-r] root@hostLinux:/root/transFile/ localFile 

重复上面的动作

验证hostWin2……hostWinN上文件的完整性

传完了验证文件的完整性(验证一遍比较放心),可以通过远程执命令统计文件的个数,大小,md5等

改进

服务器很多,敲上面的命令是不是很糟心,虽然省略了打个各个终端操作,这么多命令也很累,写脚本,自动生成命令

将win服务器列表写成配置文件

#ip::user::passwd
#x.x.x.x::yueling::yuelingp
x.x.x.x::yueling::yuelingp
x.x.x.x::yueling::yuelingp

将linux服务器列表写成配置文件

#ip::user::passwd
#x.x.x.x::yueling::yuelingp
x.x.x.x::yueling::yuelingp
#当文件比较多或者比较大时,可以配置多个linux服务器作为中转,减轻一台服务器的网络和io压力(自己把握)

将操作的文件写成配置文件

#type::path
#file
f::c:\wmsFile\a.txt
#folder
D::c:\wmsFile

文件存储的位置写成配置文件(这个一般不会用到)

比如使用常用的性能测试工具LR加载测试依赖jar包或者文件,多个机器上的文件位置肯定是固定,否则脚本就会报错,Jmeter依赖文件、参数化文件等也是一样的

核心代码

读取配置文件

package com.yueling.utils;

import(略)

/** 
* @ClassName: ReadCfgFile 
* @Description: TODO
* @author yueling 
* @date 2017年9月27日 下午2:45:26 
*  
*/
public class ReadCfgFile {
    private final static Logger logger = LoggerFactory.getLogger(ReadCfgFile.class);

    /** 
    * @Title: readTxt 
    * @Description: 读取配置文件,将结果放入arrayList对象中
    * @param @param filePath
    * @param @return
    * @return ArrayList<String>
    * @throws 
    */
    public static ArrayList<String> readTxt(String filePath) {
        ArrayList<String> arrayList = new ArrayList<String>();
        try {
            File file = new File(filePath);
            if (file.isFile() && file.exists()) {
                InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "utf-8");
                BufferedReader br = new BufferedReader(isr);
                String lineTxt = null;
                while ((lineTxt = br.readLine()) != null) {
                    if (lineTxt.trim().startsWith("#") || lineTxt.trim().equals("")) {
                        logger.info("忽略{}", lineTxt);
                    } else {
                        logger.info(lineTxt);
                        arrayList.add(lineTxt);
                    }
                }
                br.close();
                isr.close();
            } else {
                System.out.println("!");
                logger.error("【{}】文件不存在", filePath);
            }
        } catch (Exception e) {
            logger.error("打开文件异常!");
        } finally {
        }
        return arrayList;
    }

    /** 
    * @Title: processServerList 
    * @Description: 处理服务器列表,将异常剔除
    * @param @return
    * @return ArrayList<ServerListObject>
    * @throws 
    */
    public static ArrayList<ServerListObject> processServerList(String filePath) {

        ArrayList<ServerListObject> serverList = new ArrayList<ServerListObject>();


        ArrayList<String> arrServerList = readTxt(filePath);
        String pattern = ".*::.*::.*";
        String[] tmp = null;
        for (int serverIndex = 0; serverIndex < arrServerList.size(); serverIndex++) {
            ServerListObject serverListObject = new ServerListObject();
            String serverInfo = arrServerList.get(serverIndex);
            boolean isMatch = Pattern.matches(pattern, serverInfo);
            if (isMatch) {
                logger.info(serverInfo);
                tmp = serverInfo.split("::");
                int lenght = tmp.length;
                if (lenght != 3) {
                    logger.error("格式不正确!【{}】正确格式为【ip::user::passwd】", serverInfo);
                } else {
                    serverListObject.setIp(tmp[0]);
                    serverListObject.setUser(tmp[1]);
                    serverListObject.setPasswd(tmp[2]);
                    serverList.add(serverListObject);
                }
            } else {
                logger.error("格式不正确!【{}】正确格式为【ip::user::passwd】", serverInfo);
            }
        }
        return serverList;
    }

    /** 
    * @Title: processFileList 
    * @Description: 处理文件列表,将异常的剔除
    * @param @return
    * @return ArrayList<FileListObject>
    * @throws 
    */
    public static ArrayList<FileListObject> processFileList(String filePath) {
        ArrayList<FileListObject> fileList = new ArrayList<FileListObject>();


        ArrayList<String> arrFileList = readTxt(filePath);
        String pattern = ".*::.*";
        String[] tmp = null;
        for (int fileIndex = 0; fileIndex < arrFileList.size(); fileIndex++) {
            FileListObject fileListObject = new FileListObject();
            String fileInfo = arrFileList.get(fileIndex);
            boolean isMatch = Pattern.matches(pattern, fileInfo);
            if (isMatch) {
                logger.info(fileInfo);

                tmp = fileInfo.split("::");
                int lenght = tmp.length;
                if (lenght != 2) {
                    logger.error("格式不正确!【{}】正确格式为【type::path】", fileInfo);
                } else {
                    // 处理文件是否存在
                    if (tmp[0].toUpperCase().equals("f".toUpperCase())) {
                        if (isFileExists(new File(tmp[1]))) {
                            fileListObject.setType(tmp[0]);
                            fileListObject.setPath(tmp[1]);
                            fileList.add(fileListObject);
                        }
                    } else if (tmp[0].toUpperCase().equals("d".toUpperCase())) {
                        if (isDirExists(new File(tmp[1]))) {
                            fileListObject.setType(tmp[0]);
                            fileListObject.setPath(tmp[1]);
                            fileList.add(fileListObject);
                        }
                    }

                }
            } else {
                logger.error("格式不正确!【{}】正确格式为【type:path】", fileInfo);
            }
        }
        return fileList;
    }


    /** 
    * @Title: isFileExists 
    * @Description: 判断文件是否存在
    * @param @param file
    * @param @return
    * @return boolean
    * @throws 
    */
    public static boolean isFileExists(File file) {
        boolean isExistsOrNotFlag = false;
        if (file.exists()) {
            logger.info("{} file exists", file);
            isExistsOrNotFlag = true;
        } else {
            logger.info("{} file not exists", file);
            isExistsOrNotFlag = false;
        }
        return isExistsOrNotFlag;
    }


    /** 
    * @Title: isDirExists 
    * @Description: 判断文件夹是否存在
    * @param @param file
    * @param @return
    * @return boolean
    * @throws 
    */
    public static boolean isDirExists(File file) {

        boolean isExistsOrNotFlag = false;
        if (file.exists()) {
            if (file.isDirectory()) {
                logger.info("{} dir exists", file);
                isExistsOrNotFlag = true;
            } else {
                logger.info("{} the same name file exists, is not a dir", file);
                isExistsOrNotFlag = false;
            }
        } else {
            logger.info("{} is not exists", file);
            isExistsOrNotFlag = false;
        }
        return isExistsOrNotFlag;
    }

}

组装命令执行

通过上面的读取文件已经将合法的配置放入到相应的数组中,遍历组装命令即可(略)
取一段检查服务器连通性的代码为例

public static boolean winPingWinServer(ServerListObject serverListObject) {
        boolean serverAlive = false;
        Runtime rt = Runtime.getRuntime();
        Process process;
        // ping的返回中有ttl标识,通过指定的次数判断
        String contains = "TTL";
        int pingCount = 0;

        try {
            process = rt.exec("cmd.exe /c ping -n 2 " + serverListObject.getIp());
            pingCount = PrintResponseOnConsole.print(process, contains);
            if (pingCount == 2) {
                serverAlive = true;
                logger.info("localhost ping {} is alive",serverListObject.getIp());
            }else{
                logger.info("localhost ping {} is not alive",serverListObject.getIp());
            }
        } catch (IOException e) {
            logger.error("localhost ping {} exception",serverListObject.getIp());
            e.printStackTrace();
        }

        return serverAlive;
    }

使用system执行命令

使用参数控制

比如一部分命令没有必要重新执行,比如从本地上传到linux服务器,只需做一次,所以用参数控制

public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("至少需要一个参数");
            System.out.println("参数需为:<init|upload|download>");
        } else {
            try {
                filePath = directory.getCanonicalPath() + "\\config\\serverList.properties";
            } catch (IOException e) {
                e.printStackTrace();
            }
            processServerList = ReadCfgFile.processServerList(filePath);
            try {
                filePath = directory.getCanonicalPath() + "\\config\\puppetServer.properties";
            } catch (IOException e) {
                e.printStackTrace();
            }
            processPuppetServerList = ReadCfgFile.processServerList(filePath);

            try {
                filePath = directory.getCanonicalPath() + "\\config\\FileList.properties";
            } catch (IOException e) {
                e.printStackTrace();
            }
            processFileList = ReadCfgFile.processFileList(filePath);


            try {
                filePath = directory.getCanonicalPath() + "\\config\\output.bat";
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 根据传参决定执行那些功能
            if (args[0].toUpperCase().equals("init".toUpperCase())) {
                // 检查服务器部分的测试
                //testInit(directory, filePath, processServerList, processPuppetServerList, processFileList);
                //testCountFiles(processServerList, processPuppetServerList);
                //testRmFiles(processPuppetServerList);
                testInitTxt(directory, filePath, processServerList, processPuppetServerList, processFileList);
            } else if (args[0].toUpperCase().equals("upload".toUpperCase())) {
                // 测试上传文件
                testValidUploadFileToPuppetServer(directory, filePath, processServerList, processPuppetServerList,
                        processFileList);
            } else if (args[0].toUpperCase().equals("download".toUpperCase())) {
                // 测试下载文件到各个windows服务器
                testValidDownloadFileFromPuppetServer(directory, filePath, processServerList, processPuppetServerList,
                        processFileList);
            } else {
                System.out.println("参数需为:<init|upload|download>");
            }
        }
    }

打包执行

C:\Users\yueling.DANGDANG\Desktop>java -jar distribute.jar
至少需要一个参数
参数需为:<init|upload|download>

C:\Users\yueling.DANGDANG\Desktop>

附录

pscp:
PuTTY Secure Copy client
Release 0.62
Usage: pscp [options] [user@]host:source target
       pscp [options] source [source...] [user@]host:target
       pscp [options] -ls [user@]host:filespec
Options:
  -V        print version information and exit
  -pgpfp    print PGP key fingerprints and exit
  -p        preserve file attributes
  -q        quiet, don't show statistics
  -r        copy directories recursively
  -v        show verbose messages
  -load sessname  Load settings from saved session
  -P port   connect to specified port
  -l user   connect with specified username
  -pw passw login with specified password
  -1 -2     force use of particular SSH protocol version
  -4 -6     force use of IPv4 or IPv6
  -C        enable compression
  -i key    private key file for authentication
  -noagent  disable use of Pageant
  -agent    enable use of Pageant
  -batch    disable all interactive prompts
  -unsafe   allow server-side wildcards (DANGEROUS)
  -sftp     force use of SFTP protocol
  -scp      force use of SCP protocol
PsExec v1.97 - Execute processes remotely
Copyright (C) 2001-2009 Mark Russinovich
Sysinternals - www.sysinternals.com

PsExec executes a program on a remote system, where remotely executed console
applications execute interactively.

Usage: psexec [\\computer[,computer2[,...] | @file]][-u user [-p psswd][-n s][-l][-s|-e][-x][-i [session]][-c [-f|-v]][-w directory][-d][-<priority>][-a n,n,...] cmd [arguments]
     -a         Separate processors on which the application can run with
                commas where 1 is the lowest numbered CPU. For example,
                to run the application on CPU 2 and CPU 4, enter:
                "-a 2,4"
     -c         Copy the specified program to the remote system for
                execution. If you omit this option the application
                must be in the system path on the remote system.
     -d         Don't wait for process to terminate (non-interactive).
     -e         Does not load the specified account's profile.
     -f         Copy the specified program even if the file already
                exists on the remote system.
     -i         Run the program so that it interacts with the desktop of the
                specified session on the remote system. If no session is
                specified the process runs in the console session.
     -h         If the target system is Vista or higher, has the process
                run with the account's elevated token, if available.
     -l         Run process as limited user (strips the Administrators group
                and allows only privileges assigned to the Users group).
                On Windows Vista the process runs with Low Integrity.
     -n         Specifies timeout in seconds connecting to remote computers.
     -p         Specifies optional password for user name. If you omit this
                you will be prompted to enter a hidden password.
     -s         Run the remote process in the System account.
     -u         Specifies optional user name for login to remote
                computer.
     -v         Copy the specified file only if it has a higher version number
                or is newer on than the one on the remote system.
     -w         Set the working directory of the process (relative to
                remote computer).
     -x         Display the UI on the Winlogon secure desktop (local system
                only).
     -priority  Specifies -low, -belownormal, -abovenormal, -high or
                -realtime to run the process at a different priority. Use
                -background to run at low memory and I/O priority on Vista.
     computer   Direct PsExec to run the application on the remote
                computer or computers specified. If you omit the computer
                name PsExec runs the application on the local system,
                and if you specify a wildcard (\\*), PsExec runs the
                command on all computers in the current domain.
     @file      PsExec will execute the command on each of the computers listed
                in the file.
     program    Name of application to execute.
     arguments  Arguments to pass (note that file paths must be
                absolute paths on the target system).

原文链接 http://blog.csdn.net/yue530tomtom/article/details/78207506

Windows 安装版 1.5.0 beta 大小:4.4MB 更新:2014-12-20 XP/Vista/Win7/Win8 自同步是一款由国内创业团队推出的局域网P2P免费文件同步工具。处在同一个局域网下的多台电脑,可通过自同步来建立电脑里文件之间的同步关系,做到文件夹中文件的数量、内容相一致,并且不需要云和外网。此外,自同步特有的密钥加密更保证了数据的安全性。并且,其特有的分享功能又可以做到轻轻松松将同步目录分享给周围的朋友们。 软件特点 1. 无需网盘,局域同步 与市面上流行的网盘不同,自同步不需要您的设备时时刻刻连接互联网完成文件同步工作,而只需要在同一个局域网内就能完成文件同步工作。 2. 实时同步,多台互联 处于同步中的目录,只要其中一个目录发生变化,如文件/目录添加、修改、删除等操作,那么与该目录建立同步关系的其它目录也会迅速反应,进行相应的修改,保持与原目录的文件一致;此外,只需将文件放到同步目录,程序将自动上传这些文件,同时其它电脑登陆自同步时自动下载到新电脑,实现多台电脑的文件同步。 3. 目录分享,轻松同步 同步目录分享功能,可以轻松将同步目录分享给周围的朋友(无需同步口令相同)。 4. 密钥加密,保护数据 在局域网内采用AES加密方式传输数据并建立密钥,防止处于同一局域网内的非法设备窃取数据。 5. 优化传输,极速速度 千兆路由的局域网环境下传输速度最高可达70MB/s,同步过程犹如硬盘间的复制粘贴一样方便快捷。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值