Some checks failed
Build Multi-Platform Binaries / build (amd64, darwin) (push) Failing after 5m51s
Build Multi-Platform Binaries / build (amd64, windows) (push) Has been cancelled
Build Multi-Platform Binaries / build (arm64, darwin) (push) Has been cancelled
Build Multi-Platform Binaries / build (arm64, linux) (push) Has been cancelled
Build Multi-Platform Binaries / build (amd64, linux) (push) Has been cancelled
79 lines
1.7 KiB
Go
79 lines
1.7 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// PortManager 端口管理器
|
|
type PortManager struct {
|
|
mu sync.RWMutex
|
|
occupied map[int]string // port -> clientID
|
|
}
|
|
|
|
// NewPortManager 创建端口管理器
|
|
func NewPortManager() *PortManager {
|
|
return &PortManager{
|
|
occupied: make(map[int]string),
|
|
}
|
|
}
|
|
|
|
// IsPortAvailable 检测端口是否可用(系统级)
|
|
func IsPortAvailable(port int) bool {
|
|
addr := fmt.Sprintf(":%d", port)
|
|
ln, err := net.Listen("tcp", addr)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
ln.Close()
|
|
return true
|
|
}
|
|
|
|
// Reserve 预留端口给指定客户端
|
|
func (pm *PortManager) Reserve(port int, clientID string) error {
|
|
pm.mu.Lock()
|
|
defer pm.mu.Unlock()
|
|
|
|
if owner, exists := pm.occupied[port]; exists {
|
|
return fmt.Errorf("port %d already occupied by client %s", port, owner)
|
|
}
|
|
|
|
if !IsPortAvailable(port) {
|
|
return fmt.Errorf("port %d is occupied by system", port)
|
|
}
|
|
|
|
pm.occupied[port] = clientID
|
|
return nil
|
|
}
|
|
|
|
// Release 释放端口
|
|
func (pm *PortManager) Release(port int) {
|
|
pm.mu.Lock()
|
|
defer pm.mu.Unlock()
|
|
delete(pm.occupied, port)
|
|
}
|
|
|
|
// ReleaseByClient 释放指定客户端的所有端口
|
|
func (pm *PortManager) ReleaseByClient(clientID string) {
|
|
pm.mu.Lock()
|
|
defer pm.mu.Unlock()
|
|
for port, owner := range pm.occupied {
|
|
if owner == clientID {
|
|
delete(pm.occupied, port)
|
|
}
|
|
}
|
|
}
|
|
|
|
// CheckLocalService 检测本地服务是否可连接
|
|
func CheckLocalService(ip string, port int, timeout time.Duration) error {
|
|
addr := fmt.Sprintf("%s:%d", ip, port)
|
|
conn, err := net.DialTimeout("tcp", addr, timeout)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot connect to local service %s: %v", addr, err)
|
|
}
|
|
conn.Close()
|
|
return nil
|
|
}
|