使用websocket实现页面实时显示shell日志

websocket 配置

package com.sitech.cmap.comp.wsg.cntr.oracle.websocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * @ClassName:  WebSocketStompConfig
 * @Description: 
 * @author: by_csd_hlj
 * @date: 2019/1/25  13:34
 * @version: 1.0
 */
@Configuration
public class WebSocketStompConfig{
    @Bean
    public ServerEndpointExporter serverEndpointExporter()
    {
        return new ServerEndpointExporter();
    }
}

websocket
返回信息有两种形式
session.getAsyncRemote().sendText(json.toJSONString()); //异步返回
session.getBasicRemote().sendText(json.toJSONString()); //同步返回
常见异常:
The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method
具体选用哪个方法来返回信息,还需要看项目需求
返回信息,需要加上synchronized ,否则会出现 [TEXT_FULL_WRITING] 异常

package com.sitech.cmap.comp.wsg.cntr.oracle.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sitech.cmap.dao.simple.comp.mapper.OmCntrOraInsDetailMapper;
import com.sitech.cmap.dao.simple.comp.mapper.OmOracleInstanceMapper;
import com.sitech.cmap.dao.simple.comp.po.OmCntrOraInsDetail;
import com.sitech.cmap.dao.simple.comp.po.OmOracleInstance;
import com.sitech.cmap.fw.core.common.spring.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.RestController;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;

/**
 * @ClassName:
 * @Description:
 * @author: by_csd_hlj
 * @date:
 * @version: 1.0
 */
@Slf4j
@RestController
@ServerEndpoint("/v1/cntr/oracle/websocket")
public class Websocket {

    private Session session;
    private String id;

    ApplicationContext applicationContext =  SpringContextHolder.getApplicationContext();
    OmCntrOraInsDetailMapper detailMapper = (OmCntrOraInsDetailMapper) applicationContext.getBean("omCntrOraInsDetailMapper");
    OmOracleInstanceMapper instanceMapper = (OmOracleInstanceMapper) applicationContext.getBean("omOracleInstanceMapper");

    /**
     * 建立连接
     */
    @OnOpen
    public void onOpen(Session session){
        this.session = session;
        try {
            log.info("websocket 已打开。");
        } catch (Exception e){
            log.error(e.getMessage(),e);
        }
    }

    /**
     * 连接关闭
     */
    @OnClose
    public void onClose()
    {
        //webSockets.remove(this);
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.info("服务端发生了错误"+error.getMessage());
        //error.printStackTrace();
    }

    @OnMessage
    public synchronized void onMessage(String message, Session session){
        try {
        	//获取参数
            JSONObject param = JSON.parseObject(message);
            String instanceId = param.getString("id");
            String type = param.getString("type");
            String orderId = param.getString("orderId");
            this.id = instanceId;
            //获取远程主机用户、密码、ip
            OmOracleInstance ins = instanceMapper.selectByPrimaryKey(instanceId);
            OmCntrOraInsDetail d = new OmCntrOraInsDetail();
            d.setInstanceId(instanceId);
            OmCntrOraInsDetail de = detailMapper.selectOne(d);
            //获取日志路径
            String path ;
            if("start".equals(type)){
                path = de.getStartLog();
            }else{
                path = de.getStopLog();
            }
			//传参
            JSONObject json = new JSONObject();
            json.put("ip",ins.getIp());
            json.put("username",de.getUsername());
            json.put("password",de.getPassword());
            json.put("comment",path);
            json.put("id",instanceId);
            json.put("orderId",orderId);
            //websocket返回信息
            WebsocketThread thread = new WebsocketThread(this,json);
            new Thread(thread).start();

        }catch (Exception e){
            log.info("发生了错误了");
            log.error(e.getMessage(),e);
        }

    }

	//向前端发送消息
    public void sendMessage(String line,String id){
        try{
            JSONObject json = new JSONObject();
            json.put("id",id);
            json.put("msg",line);
            session.getAsyncRemote().sendText(json.toJSONString());
        }catch (Exception e){
            log.error(e.getMessage(),e);
        }
    }
}

使用线程执行ssh链接

package com.sitech.cmap.comp.wsg.cntr.oracle.websocket;

import com.alibaba.fastjson.JSONObject;
import com.sitech.cmap.dao.simple.comp.mapper.OmCntrExecHisMapper;
import com.sitech.cmap.dao.simple.comp.mapper.OmCntrOpRecordMapper;
import com.sitech.cmap.fw.core.common.spring.SpringContextHolder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;

/**
 * @ClassName:
 * @Description:
 * @author: by_csd_hlj
 * @date:
 * @version: 1.0
 */
@Slf4j
@Data
public class WebsocketThread implements Runnable{


    private Websocket websocket;
    private JSONObject json;

    ApplicationContext applicationContext =  SpringContextHolder.getApplicationContext();
    OmCntrExecHisMapper hisMapper = (OmCntrExecHisMapper) applicationContext.getBean("omCntrExecHisMapper");
    OmCntrOpRecordMapper recordMapper = (OmCntrOpRecordMapper) applicationContext.getBean("omCntrOpRecordMapper");

    public WebsocketThread(Websocket websocket, JSONObject json){
        this.websocket = websocket;
        this.json = json;
    }

    @Override
    public synchronized void run() {
        try{
        	//ssh连接
            SShAgent ssh = SShAgent.createJschSession("172.21.3.89", "comp", "comp");
            ssh.execCommand("tail -f "+json.getString("comment")+" &",websocket);
        }catch (Exception e){
            log.error(e.getMessage(),e);
        }
    }
}

sshAgent
特别注意,多线程执行日志读取时,ssh链接是不关闭的,会一直占用cpu性能,所以加上判断,如果三分钟没有返回,就关闭ssh链接

package com.sitech.cmap.comp.wsg.cntr.oracle.websocket;

import com.jcraft.jsch.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.*;

/**
 * @ClassName:
 * @Description:
 * @author: by_csd_hlj
 * @date:
 * @version: 1.0
 */
@Slf4j
@Data
public class SShAgent {

    private Session session;
    private String host;
    private int port;
    private String user;
    private String passwd;
    private String md5Cmd;


    public SShAgent(String host, int port, String user, String passwd) {
        super();
        this.host = host;
        this.port = port;
        this.user = user;
        this.passwd = passwd;
    }

    public boolean expired() throws JSchException, IOException, InterruptedException{

        Channel openChannel = session.openChannel("shell");
        PipedInputStream pis = new PipedInputStream();//服务端输入管道
        PipedOutputStream pos = new PipedOutputStream(pis);//指令写入管道
        PipedInputStream reader = new PipedInputStream();//输出管道
        PipedOutputStream out = new PipedOutputStream(reader);//服务器返回结果管道
        openChannel.setInputStream(pis);
        openChannel.setOutputStream(out);
        openChannel.connect();
        pos.write("echo 'success'\n".getBytes());
        pos.flush();
        Thread.sleep(1000);
        String str = "";
        byte [] buffer = new byte[1024];
        while(reader.read(buffer)>-1){
            str = new String(buffer);
            break;
        }
        pos.close();
        pis.close();
        out.close();
        reader.close();
        openChannel.disconnect();
        if(str.contains("Your password has expired")){
            session.disconnect();
            return true;
        }else if(str.contains("success")){
            return false;
        }else{
            return false;
        }
    }

    public void initSession() throws Exception {
        try {
            if(session==null){
                JSch jsch = new JSch();
                session = jsch.getSession(user, host, port);
                UserInfo ui = new MyUserInfo(passwd);
                session.setUserInfo(ui);
                session.setTimeout(1800000);
                session.setServerAliveInterval(1800000);
                session.connect();
            }
        } catch (Exception e) {
            closeSession();
            throw new Exception("主机密码不正确:"+host+"@"+user+"!");
        }
    }

    public void closeSession(){
        if(session!=null){
            session.disconnect();
        }
    }


    public static SShAgent createJschSession(String ip,String username,String passwd) throws Exception{
        SShAgent jsch = new SShAgent(ip,22,username,passwd);
        jsch.initSession();
        if(jsch.expired()){
            throw new Exception(ip+"@"+username+"主机密码已过期");
        }
        return jsch;
    }

    public static void closeJschSession(SShAgent client){
        if(client!=null){
            client.closeSession();
            log.info("关闭"+client.getHost()+"@"+client.getUser()+"SSH连接");
        }
    }


     public void execCommand(String command,Websocket websocket,String id) throws Exception {
        try {
            Channel channel = session.openChannel("exec");
            ((ChannelExec) channel).setCommand(command);
            channel.setInputStream(null);
            ((ChannelExec) channel).setErrStream(System.err);
            InputStream in = channel.getInputStream();
            channel.connect();
            byte[] tmp = new byte[1024];
            //进入循环时间大于3分钟,自动结束
            long currtime = System.currentTimeMillis();
            while (true) {
                long endTime = System.currentTimeMillis();
                if(endTime - currtime > 3*60*1000){
                    break;
                }
                while (in.available() > 0) {
                    int i = in.read(tmp, 0, 1024);
                    if (i < 0){
                        break;
                    }
                    //有返回时,更新一下时间,
                    currtime = System.currentTimeMillis();
                    //进程休眠,防止返回消息数量过多导致websocket报错
                    Thread.sleep(2000);
                    websocket.sendMessage( new String(tmp, 0, i),id);
                }
                if (channel.isClosed()) {
                    if (in.available() > 0){
                        continue;
                    }
                    break;
                }
            }
            channel.disconnect();
        } catch (Exception e) {
            Thread.sleep(1500);
            websocket.sendMessage( "读取日志失败!",id);
            log.error(e.getMessage(),e);
            e.printStackTrace();
            throw new Exception(getHost()+"@"+getUser()+",指令:"+command+"执行失败");
        }
    }


    public class MyUserInfo implements UserInfo {
        String passwd;

        public MyUserInfo(String passwd) {
            super();
            this.passwd = passwd;
        }

        @Override
        public String getPassphrase() {
            return null;
        }

        @Override
        public String getPassword() {
            return passwd;
        }

        @Override
        public boolean promptPassphrase(String message) {
            return true;
        }

        @Override
        public boolean promptPassword(String message) {
            return true;
        }

        @Override
        public boolean promptYesNo(String str) {
            return true;
        }

        @Override
        public void showMessage(String message) {
            System.out.println(message);
        }
    }
}

js
html页面可以根据自己的需求写,只要注意js

cons.initWebsocket = function(){
	    if ("WebSocket" in window)
	    {
	        webSocket = new WebSocket("ws://127.0.0.1:10090/cntr-service/v1/cntr/oracle/websocket");
	 
	        //连通之后的回调事件
	        webSocket.onopen = function()
	        {
	            console.log("已经连通了websocket");
	        };
	 
	        //接收后台服务端的消息
	        webSocket.onmessage = function (evt)
	        {
	        	console.log("数据已接收!");
	            var json = JSON.parse(evt.data);
	            var textarea =  $("div[data-id='"+json.id+"']").find("textarea");
	            var str = textarea.val()+json.msg;
	            textarea.text(str);
	          	textarea .scrollTop( textarea[0].scrollHeight);
	        };
	 
	        //连接关闭的回调事件
	        webSocket.onclose = function()
	        {
	            console.log("连接已关闭...");
	        };
	    }
	    else{
	        // 浏览器不支持 WebSocket
	        pluspop.alert("您的浏览器不支持 WebSocket!");
	    }
	}
	
	cons.sendMessage = function(param){
		var ids = param.ids;
		for(var i in ids){
			var message = {
				id:ids[i],
				type:param.type,
				orderId:param.orderId
			};
			webSocket.send(JSON.stringify(message));
		}
	}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 你可以使用 Vue.js 和 WebSocket 实现页面实时刷新。 首先,在你的 Vue 组件中创建一个 WebSocket 对象: ``` let socket = new WebSocket('ws://your-websocket-server'); ``` 然后,添加一个监听器来处理服务器发送的消息: ``` socket.onmessage = function (event) { // 处理服务器发送的消息 } ``` 当你的 Vue 组件中的数据发生变化时,你可以使用 WebSocket 向服务器发送消息: ``` socket.send(JSON.stringify({ // 发送的数据 })); ``` 最后,在组件销毁时,记得关闭 WebSocket 连接: ``` beforeDestroy() { socket.close(); } ``` 希望这些信息能帮到你! ### 回答2: Vue WebSocket 实现页面实时刷新长连接的过程如下: 首先,需要在Vue项目中安装WebSocket库。可以使用npm安装vue-native-websocket库,该库提供了适用于Vue的WebSocket模块。通过运行`npm install vue-native-websocket`命令进行安装。 安装完成后,在Vue项目的入口文件main.js中导入WebSocket库。通过以下代码实现: ```javascript import VueNativeSock from 'vue-native-websocket' Vue.use(VueNativeSock, 'ws://localhost:8080', { reconnection: true, // 是否自动重新连接 reconnectionAttempts: 5, // 重新连接次数 reconnectionDelay: 3000, // 重新连接延迟时间,单位ms }) ``` 这里通过Vue.use()方法将WebSocket库注册到Vue应用中,并指定连接的URL以及一些配置项,如是否自动重新连接、重新连接次数和延迟时间。 接下来,在Vue组件中使用WebSocket。可以在created()生命周期钩子函数中创建WebSocket连接。可以通过以下代码实现: ```javascript export default { created() { this.$options.sockets.onmessage = (data) => { // 接收到消息时的处理逻辑 // 刷新页面或做其他操作 } }, // ... } ``` 这里通过设置this.$options.sockets.onmessage回调函数,当接收到WebSocket服务器发送的消息时,该函数中的逻辑将被执行。在该函数中可以实现页面实时刷新或其他操作。 最后,需要在WebSocket服务器端实现消息的发送。根据具体的服务器端实现方式,可以使用相应语言和框架提供的WebSocket库,将消息发送给连接的客户端。 总结起来,Vue WebSocket 实现页面实时刷新长连接的过程包括:安装WebSocket库、在入口文件中注册WebSocket模块、在组件中使用WebSocket并处理接收到的消息、在服务器端实现消息的发送。通过这些步骤,便可以在Vue应用中实现WebSocket长连接,并根据接收到的消息实现页面实时刷新。 ### 回答3: Vue WebSocket 可以实现页面实时刷新长连接,具体步骤如下: 1. 首先,在 Vue 项目中安装 WebSocket 插件。 2. 在需要实时刷新的页面或组件中,引入 WebSocket 并创建连接。 3. 创建 WebSocket 连接后,可以监听连接的状态,比如打开、关闭、错误等。 4. 使用 WebSocket 的 onmessage 事件监听服务器发送的消息,一旦收到消息,即可触发页面或组件的刷新操作。 5. 可以通过 WebSocket 的 send 方法向服务器发送消息,实现与服务器的双向通信。 6. 在页面或组件销毁时,记得关闭 WebSocket 连接以避免资源浪费。 总结起来,Vue WebSocket 实现页面实时刷新长连接的步骤包括安装插件、创建连接、监听连接状态、监听服务器发送消息、发送消息以及关闭连接。这样可以实现页面与服务器的实时双向通信,达到页面实时刷新的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值