godoos/progress/port.go
2024-07-22 17:44:55 +08:00

174 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package progress
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os/exec"
"runtime"
"strconv"
"strings"
"sync"
)
type PortRangeResponse struct {
Start int `json:"start"`
End int `json:"end"`
EnabledPorts []int `json:"enabled_ports"`
}
func getProcessIdsOnPort(port int) ([]string, error) {
osType := runtime.GOOS
var cmd *exec.Cmd
var output []byte
var err error
switch osType {
case "darwin", "linux":
cmd = exec.Command("lsof", "-ti", fmt.Sprintf("tcp:%d", port))
case "windows":
cmd = exec.Command("powershell", "-Command", "Get-Process | Where-Object {$_.Id -eq "+strconv.Itoa(port)+"} | Select-Object -ExpandProperty Id")
default:
return nil, fmt.Errorf("unsupported operating system")
}
output, err = cmd.CombinedOutput()
if err != nil {
if exitError, ok := err.(*exec.ExitError); ok {
// 如果lsof或powershell命令找不到任何进程它会返回非零退出代码这是正常情况
if exitError.ExitCode() != 1 {
return nil, fmt.Errorf("failed to list processes on port %d: %v", port, err)
}
} else {
return nil, fmt.Errorf("failed to list processes on port %d: %v", port, err)
}
}
pids := strings.Fields(strings.TrimSpace(string(output)))
return pids, nil
}
func listEnabledPorts(portRangeStart, portRangeEnd int) ([]int, error) {
var usedPorts []int
var wg sync.WaitGroup
for i := portRangeStart; i <= portRangeEnd; i++ {
currentPort := i // 创建一个新的变量来绑定当前的i值
wg.Add(1)
go func() { // 注意这里不再直接传入port而是使用currentPort
defer wg.Done()
pids, err := getProcessIdsOnPort(currentPort)
if err != nil {
log.Printf("Error checking port %d: %v", currentPort, err)
}
if len(pids) > 0 {
usedPorts = append(usedPorts, currentPort)
}
}()
}
wg.Wait()
return usedPorts, nil
}
func killProcess(pid int) error {
osType := runtime.GOOS
var cmd *exec.Cmd
var err error
switch osType {
case "darwin", "linux":
cmd = exec.Command("kill", "-9", strconv.Itoa(pid))
case "windows":
cmd = exec.Command("taskkill", "/F", "/PID", strconv.Itoa(pid)) // /F 表示强制结束
default:
return fmt.Errorf("unsupported operating system")
}
err = cmd.Run()
if err != nil {
log.Printf("Failed to kill process with PID %d: %v", pid, err)
}
return err
}
func killAllProcessesOnPort(port int, w http.ResponseWriter) {
pids, err := getProcessIdsOnPort(port)
if err != nil {
http.Error(w, "Failed to list processes", http.StatusInternalServerError)
return
}
for _, pidStr := range pids {
if pidStr == "" {
continue
}
pidInt, err := strconv.Atoi(pidStr)
if err != nil {
log.Printf("Failed to convert PID to integer: %v", err)
continue
}
if err := killProcess(pidInt); err != nil {
log.Printf("Failed to kill process with PID %d: %v", pidInt, err)
continue
}
}
fmt.Fprintf(w, "All processes on port %d have been killed", port)
}
func KillPortHandler(w http.ResponseWriter, r *http.Request) {
portStr := r.URL.Query().Get("port")
port, err := strconv.Atoi(portStr)
if err != nil {
http.Error(w, "Invalid port number", http.StatusBadRequest)
return
}
killAllProcessesOnPort(port, w)
}
func ListPortsHandler(w http.ResponseWriter, r *http.Request) {
startStr := r.URL.Query().Get("start")
endStr := r.URL.Query().Get("end")
// 设置默认值
start := 56711
end := 56730
// 如果参数存在,则尝试转换为整数,否则使用默认值
if startStr != "" {
start, _ = strconv.Atoi(startStr)
}
if endStr != "" {
end, _ = strconv.Atoi(endStr)
}
ports, err := listEnabledPorts(start, end)
if err != nil {
http.Error(w, "Failed to list ports", http.StatusInternalServerError)
return
}
// 构造JSON响应结构体
response := PortRangeResponse{
Start: start,
End: end,
EnabledPorts: ports,
}
// 设置响应内容类型为JSON
w.Header().Set("Content-Type", "application/json")
// 编码并写入响应体
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, "Failed to encode response as JSON", http.StatusInternalServerError)
return
}
}