吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6374|回复: 46
收起左侧

[Windows] 主机状态监控程序网络版

  [复制链接]
vsyour 发表于 2022-9-6 14:58
本帖最后由 vsyour 于 2022-9-6 22:07 编辑

上次发了一个单机版的主机状态监控程序(https://www.52pojie.cn/thread-1680459-1-1.html)
这次来个网络版本的.

linux 和 windows 版本任意搭配.
只需要有一个server端用来接收client发送的消息就可以了。


运行截图.jpg




功能

server 端

启动 server 端, 监听指定端口, 生成状态信息页面.
发现接收到的状态信息中达到阈值,发送钉钉报警通知.

Usage of ./server_linux:
  -p string
        监听端口,默认8080 (default "8080")

root@test:~/run/server# ./server_linux -p 80
2022/09/06 06:49:39 服务已启动,监听端号 :80

client 端

给server 定时发送主机状态信息.

./client_linux -s "http://127.0.0.1:80"




源码:
server端:
[Golang] 纯文本查看 复制代码
package main

import (
        "flag"
        "fmt"
        "log"
        "net/http"
        "os"
        "time"

        "github.com/spf13/viper"

        "github.com/wanghuiyt/ding"

        "github.com/gin-gonic/gin"
)

type ClientInfo struct {
        HostName   string  `json:"hostname"`
        Cpu        float64 `json:"cpu"`
        Mem        float64 `json:"mem"`
        Disk       float64 `json:"disk"`
        ProcessNum uint64  `json:"processnum"`
        BootTime   string  `json:"bootTime"`
}

var htmlCode string
var serversInfo string
var num int

// 全局配置变量
var config *viper.Viper

func Index(c *gin.Context) {
        htmlCode = `<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="5" URL="#" />
<script type="text/javascript">
        window.onload=function(){
        var tfrow = document.getElementById('tfhover').rows.length;
        var tbRow=[];
        for (var i=1;i<tfrow;i++) {
                tbRow[i]=document.getElementById('tfhover').rows[i];
                tbRow[i].onmouseover = function(){
                  this.style.backgroundColor = '#f3f8aa';
                };
                tbRow[i].onmouseout = function() {
                  this.style.backgroundColor = '#ffffff';
                };
        }
};
</script>
<style type="text/css">
table.tftable {font-size:12px;color:#333333;border-width: 1px;border-color: #9dcc7a;border-collapse: collapse;}
table.tftable th {font-size:12px;background-color:#abd28e;border-width: 1px;padding: 8px;border-style: solid;border-color: #ffffff;text-align:left;}
table.tftable tr {background-color:#ffffff;}
table.tftable td {font-size:12px;border-width: 1px;padding: 8px;border-style: solid;border-color: #9dcc7a;}
</style>

<title>vsyour 监控中心</title>
</head>

<body>
<table id="tfhover" class="tftable" border="1">
<caption><b>有【%v】台服务器在线</b></caption>
<tr><th>序号</th><th>主机名</th><th>IP地址</th><th>CPU使用率</th><th>内存使用率</th><th>进程数量</th><th>开机时间</th></tr>
%v
</table>


</body>
</html>
`

        c.Header("Content-Type", "text/html; charset=utf-8")
        c.String(http.StatusOK, fmt.Sprintf(htmlCode, num, serversInfo))
        return
}

//  初始化全局map 参考 http://niliu.me/articles/1590.html
var hostList map[string]ClientInfo = make(map[string]ClientInfo)

func Add(c *gin.Context) {
        reqInfo := ClientInfo{}
        err := c.BindJSON(&reqInfo)
        if err != nil {
                c.JSONP(http.StatusNotAcceptable, "Error: "+err.Error())
                return
        }

        clientIP := c.ClientIP()
        //clientIP := reqInfo.IP  测试时直接写死方便用post man测试
        hostList[clientIP] = ClientInfo{
                reqInfo.HostName,
                reqInfo.Cpu,
                reqInfo.Mem,
                reqInfo.Disk,
                reqInfo.ProcessNum,
                reqInfo.BootTime,
        }

        n := 0
        serversInfo = ""
        num = 0
        for k, v := range hostList {
                num++
                n++
                // <tr><th>序号</th><th>主机名</th><th>IP地址</th><th>CPU占用率</th><th>内存占用</th><th>任务数量</th><th>执行命令</th></tr>
                serversInfo = serversInfo + fmt.Sprintf(`<tr><td>%v</td><td>%v</td><td>%v</td><td>%.2f%%</td><td>%.2f%%</td><td>%v</td><td>%v</td></tr>`, n, v.HostName, k, v.Cpu, v.Mem, v.ProcessNum, v.BootTime)
                //log.Println(v.CPU, v.Mem, v.Disk)
                if v.Cpu > config.GetFloat64(`checkItems.cpu`) || v.Mem > config.GetFloat64(`checkItems.mem`) || v.Disk > config.GetFloat64(`checkItems.disk`) {
                        outStr := fmt.Sprintf(`异常主机信息: HostName:%v IP:%v CPU:%v Mem:%v Disk:%v`, v.HostName, c.ClientIP(), v.Cpu, v.Mem, v.Disk)
                        log.Println(outStr)
                        sendToDingDing(outStr)
                }
        }

        //log.Println(hostList)
        c.JSONP(http.StatusOK, hostList)
        return
}

func sendToDingDing(sendContent string) {
        // 接收string类型并发送内容

        d := ding.Webhook{
                AccessToken: config.GetString("dingding.AccessToken"),
                Secret:      config.GetString("dingding.Secret"),
                EnableAt:    true, // 开启艾特
                AtAll:       true, // 艾特所有人
        }
        err := d.SendMessage(sendContent)
        if err != nil {
                fmt.Println(err)
        }

}

func main() {
        //获取项目的执行路径
        path, _ := os.Getwd()
        config = viper.New()
        config.AddConfigPath(path)     //设置读取的文件路径
        config.SetConfigName("config") //设置读取的文件名
        config.SetConfigType("yaml")   //设置文件的类型
        //尝试进行配置读取
        if err := config.ReadInConfig(); err != nil {
                log.Println(err)
                log.Println("读取配置文件出错!")
                os.Exit(1)
        }

        // Set Gin to production mode
        gin.SetMode(gin.ReleaseMode)

        // Set the router as the default one provided by Gin
        router := gin.Default()
        //router := gin.New()

        router.GET("/", Index)
        router.POST("/", Add)
        go func() {
                sleepTime := config.GetInt32("checkTime")
                // 定期对服务器信息清空,达到下线后没有心跳信息不再显示
                for {
                        time.Sleep(time.Duration(sleepTime) * time.Second)
                        //log.Println("Clear .... ")
                        serversInfo = ""
                        num = 0
                }
        }()

        // 监听端口
        var port string
        flag.StringVar(&port, "p", "8080", "监听端口,默认8080")
        flag.Parse()
        listenPort := fmt.Sprintf(":%v", port)
        log.Println("服务已启动,监听端号 " + listenPort)
        err := router.Run(listenPort)
        if err != nil {
                return
        }
}



client端:
[Golang] 纯文本查看 复制代码
package main

import (
        "bytes"
        "encoding/json"
        "flag"
        "fmt"
        "log"
        "net/http"
        "os"
        "time"

        "github.com/shirou/gopsutil/v3/cpu"
        "github.com/shirou/gopsutil/v3/disk"
        "github.com/shirou/gopsutil/v3/host"
        "github.com/shirou/gopsutil/v3/mem"
)

func GetCpuPercent() float64 {
        percent, _ := cpu.Percent(time.Second, false)
        return percent[0]
}

func GetMemPercent() float64 {
        memInfo, _ := mem.VirtualMemory()
        return memInfo.UsedPercent
}

func GetDiskPercent() float64 {
        parts, _ := disk.Partitions(true)
        diskInfo, _ := disk.Usage(parts[1].Mountpoint)
        return diskInfo.UsedPercent
}

func GetHostName() string {
        name, _ := os.Hostname()
        return name
}

func GetBootTime() string {
        // BootTime 开机时间
        t, _ := host.BootTime()
        return fmt.Sprintf("%v", time.Unix(int64(t), 0))
}

func GetProcessNum() uint64 {
        // 获取所有的pids
        infoStat, _ := host.Info()
        return infoStat.Procs
}

type ClientInfo struct {
        HostName   string  `json:"hostname"`
        Cpu        float64 `json:"cpu"`
        Mem        float64 `json:"mem"`
        Disk       float64 `json:"disk"`
        ProcessNum uint64  `json:"processnum"`
        BootTime   string  `json:"bootTime"`
}

func sendInfo(server string) {
        defer func() {
                if r := recover(); r != nil {
                        fmt.Println("发送状态信息出错,请检测server端.", r)
                }
        }()

        sendInfo := ClientInfo{
                HostName:   GetHostName(),
                Cpu:        GetCpuPercent(),
                Mem:        GetMemPercent(),
                Disk:       GetDiskPercent(),
                ProcessNum: GetProcessNum(),
                BootTime:   GetBootTime(),
        }
        //fmt.Println(sendInfo)

        body, _ := json.Marshal(sendInfo)
        resp, _ := http.Post(server, "application/json", bytes.NewBuffer(body))
        defer resp.Body.Close()
}

func main() {
        var server string
        flag.StringVar(&server, "s", "http://127.0.0.1:8080", "服务器信息")
        flag.Parse()
        log.Println("52pojie_vsyour提醒: 采集端已启动. 每10秒发送状态信息到 " + server)
        for {
                sendInfo(server)
                //timeStr := time.Now().Format("2006-01-02 15:04:05")
                //fmt.Printf("[%v] 52pojie_vsyour提醒: 本次检测已完成, [%v秒] 后再次检测!\n", timeStr, 10)
                time.Sleep(time.Duration(10) * time.Second)
        }

}




下载地址:
外链:https://vsyour.lanzoub.com/b02jl9ayb 密码:52pj

免费评分

参与人数 8吾爱币 +8 热心值 +7 收起 理由
虚空漂者 + 1 + 1 个人建议,把2个做成一个一键启动,可以隐藏在软件,并带设置IP和端口,提.
fnhc25181 + 1 + 1 热心回复!
zsy0022041 + 1 + 1 谢谢@Thanks!
alderaan + 1 + 1 热心回复!
老道创 + 1 我很赞同!
lvjs99999 + 1 + 1 谢谢@Thanks!
爱的太迟 + 1 + 1 用心讨论,共获提升!
hf1986110 + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

bachelor66 发表于 2022-9-6 16:44
可以加上温度监测吗?                                                               

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
vsyour + 1 + 1 我很赞同!

查看全部评分

Mr_ZJL 发表于 2022-9-29 11:02
C:\client>client_win.exe -s "http://192.168.190.20:9731"
2022/09/29 10:57:54 52pojie_vsyour提醒: 采集端已启动. 每10秒发送状态信息到 http://192.168.190.20:9731
发送状态信息出错,请检测server端. runtime error: index out of range [1] with length 1
不知道怎么回事,提示报错,都是window环境。在另外电脑测试就没问题,报错的是Windows server 环境
lnshijia 发表于 2022-9-6 15:13
powerwht 发表于 2022-9-6 15:30
这个看着还真是不错
dork 发表于 2022-9-6 15:31
对于大量VPS主来说,还是很有用的。。。。。

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
vsyour + 1 + 1 我很赞同!

查看全部评分

xuebinboy 发表于 2022-9-6 15:37
不错,简洁 有用
haohanxingkong 发表于 2022-9-6 16:00
这个看着真不错
ideapad 发表于 2022-9-6 16:36
感谢分享。不错的软件
kidwords 发表于 2022-9-6 17:02
没有硬盘,暂时先观望一下吧,
cn449712926 发表于 2022-9-6 17:26
谢谢分享 学习下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 提醒:禁止复制他人回复等『恶意灌水』行为,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2022-12-4 11:04

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表