当前的需求是获取当前wan网口的进口和出口流量,页面每隔5秒钟去轮询一次,实现如下图所示的效果:
1.获取进出口流量的脚本
脚本中的enp2s0 是WAN口的名称
#! /bin/bash
for val in $(ifconfig -a | grep "BROADCAST" | awk '{print $1}'|awk -F ":" '{print $1}')
do
if [ "$val" == "enp2s0" ]; then
addr="no"
link_stat=$(ethtool $val | grep 'Link detected' | awk '{print $3}')
rx=$(ifconfig $val | grep "RX packets" |awk '{print $5}')
tx=$(ifconfig $val | grep "TX packets" |awk '{print $5}')
echo $val"-"$addr"-"$rx"-"$tx"-"$link_stat"#"
fi
done
2.Java根据脚本获取数据
- 业务实现层代码
/**
* 默认sh文件名 getEthIF.sh
* sh %s/getEthIF.sh
*/
private static final String SH_COMMAND = "sh %s/getEthIF.sh";
/**
* 存放上一次查询的各网卡网络流量统计值
*/
private Map<String, Map<String, Long>> networkFlowMap = new HashMap<>(16);
@Override
public List<NetMonitorVO> getNetworkSituation() {
String shScriptPath = "/usr/local/nss";
String nowTimeString = DateUtils.getTimeString();
String command = String.format(SH_COMMAND, shScriptPath);
List<NetMonitorVO> networkSituationVOList = new ArrayList<>();
try {
String callCmdResult = JavaLinuxCmdUtil.onlyCallCmd(command);
if (StringUtils.isEmpty(callCmdResult)) {
throw new BusinessException("Abnormal execution of sh script");
}
String[] netWorkInterfacesDatas = callCmdResult.split("\n");
//遍历每个网口的流量信息
//网卡接口名称
String ethName = "";
//入流量
Long inRateOfFlow = 0L;
//出流量
Long outRateOfFlow = 0L;
// 上次查询的入口流量
Long lastInRateOfFlow = 0L;
// 上次查询的出口流量
Long lastOutRateOfFlow = 0L;
// 上次查询的入口流量的差值
Long diffInFlow = 0L;
// 上次查询的出口流量的差值
Long diffOutFlow = 0L;
NetMonitorVO.InEthFlow inEthFlow = null;
NetMonitorVO.OutEthFlow outEthFlow = null;
NetMonitorVO networkSituationVO = null;
for (String eth : netWorkInterfacesDatas) {
if (StringUtils.isBlank(eth)) {
continue;
}
String[] ethInfos = eth.trim().split("-");
//满足数组长度,才能正确获取结果
if (ethInfos.length == 5) {
//ens192-192.168.103.191/-504058335-155566011-yes#
// 网卡接口名称-IP/-入流量总和-出流量总和
ethName = ethInfos[0];
networkSituationVO = new NetMonitorVO();
networkSituationVO.setEthName(ethName);
// 进口流量
inRateOfFlow = StringUtils.isNumeric(ethInfos[2]) ? Long.parseLong(ethInfos[2]) : 0L;
// 出口流量
outRateOfFlow = StringUtils.isNumeric(ethInfos[3]) ? Long.parseLong(ethInfos[3]) : 0L;
inEthFlow = new NetMonitorVO.InEthFlow();
outEthFlow = new NetMonitorVO.OutEthFlow();
inEthFlow.setDateTime(nowTimeString);
outEthFlow.setDateTime(nowTimeString);
//未记录上一次流量时,将当前值存入map,并向前端返回0为流量统计结果
if (!networkFlowMap.containsKey(ethName)) {
Map<String, Long> flowMap = new HashMap<>();
flowMap.put("inRateOfFlow", inRateOfFlow);
flowMap.put("outRateOfFlow", outRateOfFlow);
networkFlowMap.put(ethName, flowMap);
inEthFlow.setCount(0L);
outEthFlow.setCount(0L);
} else {
lastInRateOfFlow = networkFlowMap.get(ethName).get("inRateOfFlow");
lastOutRateOfFlow = networkFlowMap.get(ethName).get("outRateOfFlow");
diffInFlow = inRateOfFlow - lastInRateOfFlow;
diffOutFlow = outRateOfFlow - lastOutRateOfFlow;
//如果此次采集值比上一次值低,可能由于此网口重新启动过,需要重新统计流量,并将向前台返回0为些网口的流量统计值
if (diffInFlow < 0) {
inEthFlow.setCount(0L);
} else {
inEthFlow.setCount(diffInFlow / 1024);
}
if (diffOutFlow < 0) {
outEthFlow.setCount(0L);
} else {
outEthFlow.setCount(diffOutFlow / 1024);
}
}
networkSituationVO.setInEthFlow(inEthFlow);
networkSituationVO.setOutEthFlow(outEthFlow);
Map<String, Long> flowMap = new HashMap<>();
flowMap.put("inRateOfFlow", inRateOfFlow);
flowMap.put("outRateOfFlow", outRateOfFlow);
networkFlowMap.put(ethName, flowMap);
networkSituationVOList.add(networkSituationVO);
}
}
} catch (Exception e) {
throw new BusinessException("Abnormal execution of sh script");
}
return networkSituationVOList;
}
- NetMonitorVO代码
import lombok.Data;
import java.io.Serializable;
@Data
public class NetMonitorVO implements Serializable {
private static final long serialVersionUID = 1L;
private String ethName;
private InEthFlow inEthFlow;
private OutEthFlow outEthFlow;
/**
* 封装入口流量数据
*/
@Data
public static class InEthFlow {
private String dateTime;
private Long count;
}
/**
* 封装出口流量数据
*/
@Data
public static class OutEthFlow {
private String dateTime;
private Long count;
}
}
- DateUtils工具类
/**
* HH:mm:ss
*/
private static final DateTimeFormatter FORMATTER_TIME = DateTimeFormatter.ofPattern("HH:mm:ss");
/**
* 获取时分秒毫秒字符串
* * @return HH:mm:ss
*/
public static String getTimeString() {
String timeString = FORMATTER_TIME.format(LocalDateTime.now());
return timeString;
}
- JavaLinuxCmdUtil工具类
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class JavaLinuxCmdUtil {
public static String onlyCallCmd(String cmd) {
try {
String[] command = {"/bin/sh", "-c", cmd};
Process process = Runtime.getRuntime().exec(command);
String sb = getCallResult(process);
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private static String getCallResult(Process process) throws Exception {
int exitCode = process.waitFor();
// 取得命令结果的输出流
InputStream is = process.getInputStream();
// 用一个读输出流类去读
InputStreamReader isr = new InputStreamReader(is);
// 用缓冲器读行
BufferedReader br = new BufferedReader(isr);
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
isr.close();
br.close();
return sb.toString();
}
}
3.前端将折线图封装成组件
组件:WanFlowChart.vue
<template>
<div id="flowMonitoring" :class="className" :style="{height:height,width:width}" />
</template>
<script>
import * as echarts from 'echarts'
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '350px'
},
autoResize: {
type: Boolean,
default: true
},
chartData: {
type: Object,
required: true
}
},
data() {
return {
chart: null
}
},
watch: {
chartData: {
deep: true,
handler(val) {
this.setOptions(val)
}
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(document.getElementById('flowMonitoring'))
console.log(this.chartData)
this.setOptions(this.chartData)
},
setOptions({ xAxis, inSeries, outSeries } = {}) {
const interval = Math.round(xAxis.length / 7) - 1
this.chart.setOption({
color: ['#4c8ff1', '#1cd798'],
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '6%',
bottom: '6%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: xAxis,
axisTick: {
alignWithLabel: true
},
axisLabel: {
interval: interval,
color: '#858fa6'
},
splitLine: {
lineStyle: {
width: 1,
color: '#E2E2E2'
}
},
axisLine: {
show: false,
lineStyle: {
width: 1,
color: '#E2E2E2'
}
}
},
yAxis: {
type: 'value',
axisLabel: {
color: '#858fa6',
formatter: '{value} kb/s'
},
splitLine: {
lineStyle: {
width: 1,
color: '#E2E2E2'
}
},
axisTick: {
show: false
},
axisLine: {
lineStyle: {
width: 0,
color: '#E2E2E2',
show: false
}
}
},
series: [
{
name: 'Internal flow',
type: 'line',
data: inSeries,
smooth: true,
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: '#74AAF8'
}, {
offset: 1, color: '#fff'
}],
global: false
}
}
},
{
name: 'External flow',
type: 'line',
data: outSeries,
smooth: true,
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0, color: '#31CF9A'
}, {
offset: 1, color: '#fff'
}],
global: false
}
}
}
]
})
}
}
}
</script>
父页面引用子组件:
<template>
<div class="app-container">
<wan-flow-chart :chart-data="flowMonitorData"></wan-flow-chart>
</div>
</template>
import { listNetworkSituation } from '@/api/state/state'
import WanFlowChart from './components/WanFlowChart'
export default {
components: { WanFlowChart },
data() {
flowMonitorData: {
xAxis: [],
inSeries: [],
outSeries: []
}
},
mounted() {
this.getNetList()
// 每隔5秒轮询一次
const timer = setInterval(() => {
this.getNetList()
}, 5000)
this.$once('hook:beforeDestroy', () => {
clearInterval(timer)
})
},
methods: {
getNetList() {
this.loading = true
listNetworkSituation().then(response => {
if (response.code === 200) {
this.loading = false
const list = response.data
if (list && list.length > 0) {
list.forEach((item, index) => {
this.flowMonitorData.xAxis.push(item.inEthFlow.dateTime)
this.flowMonitorData.inSeries.push(item.inEthFlow.count)
this.flowMonitorData.outSeries.push(item.outEthFlow.count)
})
}
}
})
}
}
}