docker里Java服务执行ping命令模拟流式输出

这篇具有很好参考价值的文章主要介绍了docker里Java服务执行ping命令模拟流式输出。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

业务场景

  • 我们某市的客户,一直使用CS版本的信控平台,直接安装客户Windows server服务器上,主要对信号机设备进行在线管理、方案配时、管控等
  • 其中有一项功能,在网络波动情况,对信号机管控失败,判断信号机是否在线。大致方法是直接调用Windows的dos窗口,发送 ping ip的命令,显示网络情况
  • 我们新的信控平台使用Spring Cloud微服务架构,使用Spring Boot构建Java服务,使用google的jib插件打成docker镜像包
  • 我们使用docker虚拟化部署,使用docker-compose统一管理所有服务,部署在Linux服务器里
  • 客户很喜欢之前的功能,需要我们在新平台里实现这个功能,调用dos窗口,ping网络
  • 而我们新平台是B/S架构,浏览器是很难调用Windows组件去弹出窗口实现ping功能,而且我们也没有限制一定使用的是Windows电脑访问,有网有浏览器就行
  • ping功能无论Windows还是Linux,都是有的,至于界面展现,只能自己实现了
    docker里Java服务执行ping命令模拟流式输出,java,Linux,docker,java,容器

处理解决

实现ping功能并实时返回输出

  • 代码实现,有两个核心功能点
  • 一是根据不同的操作系统,执行对应的系统命令,进行结果接收与解析
    • 对于第一个问题,Java有现成的类库,使用Runtime.getRuntime().exec(ping命令)即可
    • 对于Windows服务器,需要使用GB2312解析命令执行结果
    • 对于Linux 服务器,需要使用UTF_8解析命令执行结果
    • 对于ServletOutputStream.println输出中文字符串报错Not an ISO 8859-1 character问题,可以使用PrintWriter.println输出代替
    • 也可以在ServletOutputStream.println输出时输出字符数组(string.getBytes()
  • 二是流式输出到请求端,模拟再现一秒一次的逐步展示的效果
    • 对于第二个问题,核心是命令执行的结果输出流,要实时的返回给请求端,请求端能接收到
    • 主要是获取流,然后按行读取,按行flush()即可返回给请求端
    • 对于请求端实时渲染,需要在代码的response里指定ContentTypetext/event-stream,这样flush刷新的返回流,才能实时被前端浏览器接收到(ChatGPT流式输出也是使用的这种content-type
    • 一开始是考虑使用multipart,完全不行,流flush后,浏览器无法获取,只能在流输出完成后,浏览器才能获取到
  • 具体代码如下:
    /**
     * 获取信号机的网络状态
     * @param ip
     * @param count
     * @param response
     */
    @GetMapping("/ping/start")
    public void ping(String ip, Integer count, HttpServletResponse response) {
        logger.info("ping 信号机【{}】 开始 ......", ip);
        response.setStatus(HttpServletResponse.SC_OK);
        response.setContentType("text/event-stream");
        response.setCharacterEncoding("UTF-8");
        String line = null;
        Process pro = null;
        BufferedReader buf = null;
        try {
            if (null == count) {
                count = 4;
            }
            String osName = System.getProperty("os.name");
            if (osName.toLowerCase().contains("windows")){
                pro = Runtime.getRuntime().exec("ping -n " + count + " " + ip);
                buf = new BufferedReader(new InputStreamReader(pro.getInputStream(), "GB2312"));
            } else if (osName.toLowerCase().contains("linux")){
                pro = Runtime.getRuntime().exec("ping -c " + count + " " + ip);
                buf = new BufferedReader(new InputStreamReader(pro.getInputStream(), StandardCharsets.UTF_8));
            }
            PrintWriter out = response.getWriter();
            while (null != buf && (line = buf.readLine()) != null){
                out.println(line);
                out.flush();
            }
            logger.info("执行ping请求结束!");
            out.close();
        } catch (Exception e){
            logger.error("执行ping命令出现异常");
            e.printStackTrace();
        }finally {
            if (null != pro){
                pro.destroy();
            }
        }
    }

实现长ping和中断请求

  • 主要是在请求时传输一个唯一命令id,缓存到内存里
  • 当命令执行完成,或者接收到打断请求时,调用destroy()打断循环,结束请求
  • 当然,可以尝试使用kill -2去模拟CTRL + C的打断,可以使用Runtime.getRuntime().exec(中断命令)打断试下,我的代码已经满足自己的需求了,就没再尝试,有兴趣的小伙伴可以试一下
  • 具体代码如下:

package com.newatc.api.rest;


import com.newatc.api.signalcontrol.dto.PingRequestVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 调用系统命令并返回
 *
 * @author yanyulin
 * @date 2024-1-16 15:11:55
 */
@RestController
@RequestMapping(value = "/api/syscmd")
public class SysCmdController {

    private static final Logger logger = LoggerFactory.getLogger(SysCmdController.class);

    /**
     * 命令id-执行过程map
     */
    public static final Map<String, Boolean> COMMAND_REQUEST_MAP = new HashMap<>();
    /**
     * 开始信号机的网络状态诊断
     */
    @PostMapping("/ping/start")
    public void ping(@RequestBody PingRequestVO pingRequest, HttpServletResponse response) {
        String ip = pingRequest.getIp();
        String cmdId = pingRequest.getCmdId();
        Integer count = pingRequest.getCount();
        logger.info("ping 信号机【{}】 开始 ......", ip);
        response.setStatus(HttpServletResponse.SC_OK);
        response.setContentType("text/event-stream");
        response.setCharacterEncoding("UTF-8");
        String line = null;
        Process pro = null;
        BufferedReader buf = null;
        try {
            if (null == count) {
                count = 4;
            }
            if (count > 50) {
                count = 50;
            }
            String osName = System.getProperty("os.name");
            if (osName.toLowerCase().contains("windows")){
                pro = Runtime.getRuntime().exec("ping -n " + count + " " + ip);
                buf = new BufferedReader(new InputStreamReader(pro.getInputStream(), "GB2312"));
            } else if (osName.toLowerCase().contains("linux")){
                pro = Runtime.getRuntime().exec("ping -c " + count + " " + ip);
                buf = new BufferedReader(new InputStreamReader(pro.getInputStream(), StandardCharsets.UTF_8));
            }
            COMMAND_REQUEST_MAP.put(cmdId, true);
            PrintWriter out = response.getWriter();
            while (null != buf && (line = buf.readLine()) != null){
                out.println(line);
                out.flush();
                if (!COMMAND_REQUEST_MAP.get(cmdId)) {
                    pro.destroy();
                }
            }
            logger.info("执行ping请求结束!");
            out.close();
        } catch (Exception e){
            logger.error("执行ping命令出现异常");
            e.printStackTrace();
        }finally {
            if (null != pro){
                pro.destroy();
            }
            COMMAND_REQUEST_MAP.remove(cmdId);
        }
    }

    /**
     * 打断命令执行状态
     */
    @PostMapping("/ping/stop")
    public void ping(@RequestBody PingRequestVO requestVO) {
        COMMAND_REQUEST_MAP.put(requestVO.getCmdId(), false);
    }
}

docker容器找不到ping命令处理

  • 我们打包导出的docker镜像,无法使用ping命令,报错,找不到这个命令bash: ping:command not found
  • 我们使用的是极简镜像eclipse-temurin:11-jre-focal,这个版本里的ubuntu没有安装不需要的命令
  • 具体可以参考我的这篇博文:《自制Java镜像发布到dockerhub公网使用》
  • 也可以直接使用我发布到公网的包含ping命令的jre11镜像文件1363241277/jre11:11-jre-focal
  • 主要思路,就是打包使用的原始Java镜像里,要已经安装ping等需要的命令

文章来源地址https://www.toymoban.com/news/detail-804082.html

到了这里,关于docker里Java服务执行ping命令模拟流式输出的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java调用GPT实现可连续对话和流式输出

    源码及更详细的介绍说明参见Git上的 README.md 文档 https://github.com/asleepyfish/chatgpt 本文Demo(SpringBoot和Main方法Demo均包括)的Git地址:https://github.com/asleepyfish/chatgpt-demo 流式输出结合Vue前端的Demo的Git地址:https://github.com/asleepyfish/chatgpt-vue 后续使用方法和api版本更新均在Github的READM

    2024年02月09日
    浏览(43)
  • java实现连接远程服务器,并可以执行shell命令

    你可以使用Java中的SSH库来连接远程服务器并执行shell命令。下面是一个简单的示例代码: 请注意替换 your_host , your_username , your_password 和 your_shell_command 为实际的远程服务器信息和要执行的shell命令。该示例代码使用JSch库来建立SSH连接并执行命令。

    2024年01月20日
    浏览(64)
  • Java调用ChatGPT(基于SpringBoot和Vue)实现可连续对话和流式输出

    源码及更详细的介绍说明参见Git上的 README.md 文档 https://github.com/asleepyfish/chatgpt 本文Demo(SpringBoot和Main方法Demo均包括)的Git地址:https://github.com/asleepyfish/chatgpt-demo 流式输出结合Vue前端的Demo的Git地址:https://github.com/asleepyfish/chatgpt-vue 后续使用方法和api版本更新均在Github的READM

    2024年02月09日
    浏览(51)
  • docker内部ping和ip命令的使用

    1、ping 1.1首先解决权限问题 docker 中执行: apt-get update 报错: E: List directory /var/lib/apt/lists/partial is missing. - Acquire (13: Permission denied) 问题原因 :权限不足,请使用 root 用户 解决方案 :0 表示 root 用户 2.2 ping解决 问题原因 : 解决方法 : 先进入docker 更新apt 安装插件ping : 2、

    2024年02月15日
    浏览(33)
  • linux服务器禁止ping命令,linux服务器禁ping如何解除

      我是艾西,在我们搭建网站或做某些程序时,不少人会问禁ping是什么意思,怎么操作的对于业务有哪些好处等,今天艾西一次给你们说清楚。 禁PING的意思是:不允许电脑、设备或服务器使用PING功能。一般情况下电脑、防火墙、服务器都是允许PING功能的,不需要特别设置

    2023年04月20日
    浏览(50)
  • Java调用ChatGPT(基于SpringBoot和Vue)实现连续对话、流式输出和自定义baseUrl

    源码及更详细的介绍说明参见Git上的 README.md 文档 https://github.com/asleepyfish/chatgpt 本文Demo(SpringBoot和Main方法Demo均包括)的Git地址:https://github.com/asleepyfish/chatgpt-demo 流式输出结合Vue前端的Demo的Git地址:https://github.com/asleepyfish/chatgpt-vue 后续使用方法和api版本更新均在Github的READM

    2024年02月16日
    浏览(40)
  • 【Python】在代码中执行终端命令并获取输出和运行状态

      在Python编程过程中,我们可能会遇到需要在终端命令行执行某个命令并获取其输出的操作,我们首先想到可能就是C语言中的 system(\\\"pause\\\"); 语句,确实,python当中也有类似的命令,同时,为了满足进一步的需求,比如判断指令是否执行完毕或者是得到执行输出的内容。  

    2024年02月05日
    浏览(54)
  • 快速分隔文件(split),合并文件(paste)的命令;eval(先扫描输出在执行)命令

    语法格式: split 【选项】 参数 原始文件 拆分后文件名前缀 常用选项 -l:以行数拆分 -b:以大小拆分 以行数拆分 以大小拆分 语法格式: paste 【选项】 参数 文件 常用选项 -d :指定分隔符默认为Tab -s :横向排列文件 paste命令 paste -d 修改间隔符 paste -s 横向排列 例:将两个

    2024年02月04日
    浏览(43)
  • Java调用ChatGPT(基于SpringBoot),实现可连续对话和流式输出的ChatGPT API(可自定义实现AI助手)

    源码及更详细的介绍说明参见Git上的 README.md 文档 https://github.com/asleepyfish/chatgpt 本文Demo(SpringBoot和Main方法Demo均包括)的Git地址:https://github.com/asleepyfish/chatgpt-demo 流式输出结合Vue前端的Demo的Git地址:https://github.com/asleepyfish/chatgpt-vue 后续使用方法和api版本更新均在Github的READM

    2023年04月13日
    浏览(57)
  • linux中ping命令网络不可达或ping www.baidu.com未知的名称与服务

    linux提示网络不可达/未知的名称与服务 检查静态ip地址、网关、子网掩码 、域名解析地址是否配置完成,是否设为静态  重启网络: 1.查看网卡: 2.查看网关    发现此时网关并未设置成功  添加网关 设置完成  ping通

    2024年02月11日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包