From d9eb9acd9b82f39797a18b3f3adb3955c88a0225 Mon Sep 17 00:00:00 2001 From: 4566704 <4566704@qq.com> Date: Sun, 20 Sep 2026 02:29:36 +0800 Subject: [PATCH] =?UTF-8?q?feat(process):=20=E8=BF=9C=E7=A8=8B=E8=BF=9B?= =?UTF-8?q?=E7=A8=8B=E7=AE=A1=E7=90=86=E2=80=94=E2=80=94GET=20/process/lis?= =?UTF-8?q?t(gopsutil=20=E5=85=A8=E9=87=8F=E6=9E=9A=E4=B8=BE,=20=E6=8C=89?= =?UTF-8?q?=E5=86=85=E5=AD=98=E9=99=8D=E5=BA=8F)=20+=20POST=20/process/kil?= =?UTF-8?q?l(=E5=90=8D=E7=A7=B0=E9=98=B2=E8=AF=AF=E6=9D=80=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C,=20Windows=20taskkill=20/T=20=E5=85=9C=E5=BA=95?= =?UTF-8?q?=E5=BC=BA=E6=9D=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 与 file/shell 同为被控 HTTP 能力: BS 与客户机被控端共用, 经 zonat 隧道 + web-gateway typ=process 反代出网 --- process/process_http.go | 118 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 process/process_http.go diff --git a/process/process_http.go b/process/process_http.go new file mode 100644 index 0000000..6148f3c --- /dev/null +++ b/process/process_http.go @@ -0,0 +1,118 @@ +// 远程进程管理:进程列表 / 结束进程。 +// gopsutil 跨平台实现,与 file/shell 同为被控 HTTP 能力——BS 与客户机被控端共用, +// 经 zonat 隧道 + web-gateway 反代出网(typ=process,页面 www/process.html)。 + +package process + +import ( + "net/http" + "os/exec" + "runtime" + "sort" + "strconv" + + "github.com/gin-gonic/gin" + "github.com/shirou/gopsutil/v3/process" +) + +// ProcItem 进程列表行。 +type ProcItem struct { + Pid int32 `json:"pid"` + Name string `json:"name"` + Status string `json:"status"` + User string `json:"user"` + CPUPercent float64 `json:"cpuPercent"` // 进程存活期累计 CPU 占用率(gopsutil 口径) + MemRSS uint64 `json:"memBytes"` // 物理内存占用(字节) + MemPercent float32 `json:"memPercent"` + CreateTime int64 `json:"createTime"` // 启动时间(Unix 毫秒) + Exe string `json:"exe"` + Cmdline string `json:"cmdline"` +} + +// RegisterRoutersProcess 装配进程管理路由: GET /process/list, POST /process/kill。 +func RegisterRoutersProcess(r *gin.RouterGroup) { + r.GET("/process/list", listProcesses()) + r.POST("/process/kill", killProcess()) +} + +// listProcesses 全量进程列表(按内存占用降序)。 +func listProcesses() gin.HandlerFunc { + return func(c *gin.Context) { + procs, err := process.Processes() + if err != nil { + c.JSON(http.StatusOK, gin.H{"code": 1, "msg": "枚举进程失败: " + err.Error(), "data": nil}) + return + } + items := make([]ProcItem, 0, len(procs)) + for _, p := range procs { + item := ProcItem{Pid: p.Pid} + if name, e := p.Name(); e == nil { + item.Name = name + } + if st, e := p.Status(); e == nil && len(st) > 0 { + item.Status = st[0] + } + if u, e := p.Username(); e == nil { + item.User = u + } + if cpu, e := p.CPUPercent(); e == nil { + item.CPUPercent = cpu + } + if mem, e := p.MemoryInfo(); e == nil { + item.MemRSS = mem.RSS + } + if mp, e := p.MemoryPercent(); e == nil { + item.MemPercent = mp + } + if ct, e := p.CreateTime(); e == nil { + item.CreateTime = ct + } + if exe, e := p.Exe(); e == nil { + item.Exe = exe + } + if cmd, e := p.Cmdline(); e == nil { + item.Cmdline = cmd + } + items = append(items, item) + } + sort.Slice(items, func(i, j int) bool { return items[i].MemPercent > items[j].MemPercent }) + c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "OK", "data": gin.H{"list": items}}) + } +} + +// killProcess 结束进程: {pid: 必填, name: 可选校验(防 pid 复用误杀)}。 +// Windows 上 gopsutil 权限不足时回退 taskkill /F /T(连子进程树强杀)。 +func killProcess() gin.HandlerFunc { + return func(c *gin.Context) { + var req struct { + Pid int32 `json:"pid"` + Name string `json:"name"` + } + if err := c.ShouldBindJSON(&req); err != nil || req.Pid <= 0 { + c.JSON(http.StatusOK, gin.H{"code": 1, "msg": "参数错误: pid 必填且为正整数", "data": nil}) + return + } + p, err := process.NewProcess(req.Pid) + if err != nil { + c.JSON(http.StatusOK, gin.H{"code": 1, "msg": "进程不存在: " + err.Error(), "data": nil}) + return + } + if req.Name != "" { + if name, e := p.Name(); e == nil && name != "" && name != req.Name { + c.JSON(http.StatusOK, gin.H{"code": 1, "msg": "进程名不匹配(实际 " + name + "), 已拒绝结束", "data": nil}) + return + } + } + if err := p.Kill(); err != nil { + if runtime.GOOS != "windows" { + c.JSON(http.StatusOK, gin.H{"code": 1, "msg": "结束进程失败: " + err.Error(), "data": nil}) + return + } + if out, e := exec.Command("taskkill", "/F", "/T", "/PID", strconv.Itoa(int(req.Pid))).CombinedOutput(); e != nil { + c.JSON(http.StatusOK, gin.H{"code": 1, "msg": "结束进程失败: " + err.Error() + "; taskkill: " + string(out), "data": nil}) + return + } + } + c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "OK", "data": gin.H{"pid": req.Pid}}) + } +}