快速 Ping 局域網設備

@zgcwkj  2025年03月23日

分類:

代碼 其它 

快速 Ping 局域網設備,然後再通過 ARP 命令就可以知道某個設備有沒有在線了(golang

源碼如下

package main

import (
    "context"
    "fmt"
    "net"
    "os/exec"
    "strings"
    "sync"
    "time"
)

// 網絡信息
type NetworkInfo struct {
    IP      string // 網卡IP
    Network string // 網絡前綴
    Name    string // 網卡名稱
    Status  string // 網卡狀態
}

// Ping掃描器
type PingScanner struct {
    networks []NetworkInfo       // 網絡信息
    workers  int                 // 並發數
    timeout  time.Duration       // 超時時間
    results  map[string][]string // 掃描結果
    mutex    sync.RWMutex        // 互斥鎖
}

// 獲取本地IP地址
func (ps *PingScanner) getLocalIPs() error {
    ifaces, err := net.Interfaces()
    if err != nil {
        return fmt.Errorf("獲取網卡接口失敗: %v", err)
    }
    // 遍曆網卡接口
    for _, iface := range ifaces {
        if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagRunning == 0 {
            continue
        }
        // 獲取網卡地址
        addrs, err := iface.Addrs()
        if err != nil {
            continue
        }
        // 遍曆網卡地址
        for _, addr := range addrs {
            if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
                if ip := ipnet.IP.To4(); ip != nil {
                    ipParts := strings.Split(ip.String(), ".")
                    if len(ipParts) == 4 {
                        networkPrefix := strings.Join(ipParts[:3], ".")
                        status := "已連接"
                        if iface.Flags&net.FlagRunning == 0 {
                            status = "已啟用但未連接"
                        }
                        ps.networks = append(ps.networks, NetworkInfo{
                            IP:      ip.String(),
                            Network: networkPrefix,
                            Name:    iface.Name,
                            Status:  status,
                        })
                    }
                }
            }
        }
    }
    // 檢查是否找到有效的網絡接口
    if len(ps.networks) == 0 {
        return fmt.Errorf("未找到有效的網絡接口")
    }
    return nil
}

// Ping主機
func (ps *PingScanner) pingHost(ctx context.Context, ip string) bool {
    ctx, cancel := context.WithTimeout(ctx, ps.timeout)
    defer cancel()
    // 執行ping命令
    cmd := exec.CommandContext(ctx, "ping", "-n", "1", "-w", "500", ip)
    err := cmd.Run()
    return err == nil
}

// worker函數
func (ps *PingScanner) worker(ctx context.Context, jobs <-chan string, wg *sync.WaitGroup) {
    defer wg.Done()
    // 處理掃描任務
    for {
        select {
        case ip, ok := <-jobs:
            if !ok {
                return
            }
            if ps.pingHost(ctx, ip) {
                networkPrefix := strings.Join(strings.Split(ip, ".")[:3], ".")
                ps.mutex.Lock()
                ps.results[networkPrefix] = append(ps.results[networkPrefix], ip)
                ps.mutex.Unlock()
            }
        case <-ctx.Done():
            return
        }
    }
}

// 掃描網絡
func (ps *PingScanner) scanNetwork(ctx context.Context, network NetworkInfo) {
    jobs := make(chan string, 256)
    var wg sync.WaitGroup
    // 啟動worker池
    for i := 0; i < ps.workers; i++ {
        wg.Add(1)
        go ps.worker(ctx, jobs, &wg)
    }
    // 發送掃描任務
    go func() {
        for i := 0; i < 256; i++ {
            ip := fmt.Sprintf("%s.%d", network.Network, i)
            select {
            case jobs <- ip:
            case <-ctx.Done():
                return
            }
        }
        close(jobs)
    }()
    // 等待所有worker完成
    wg.Wait()
}

// 打印掃描結果
func (ps *PingScanner) printResults() {
    totalCount := 0
    fmt.Println("\n掃描結果:")
    for i, network := range ps.networks {
        devices := ps.results[network.Network]
        fmt.Printf("\n網段 %d: %s.0/24 (接口IP: %s)\n", i+1, network.Network, network.IP)
        fmt.Printf("發現 %d 個在線設備:\n", len(devices))
        for j, ip := range devices {
            fmt.Printf("  [%d] %s\n", j+1, ip)
        }
        totalCount += len(devices)
    }
    fmt.Printf("\n掃描完成,所有網段共發現 %d 個在線設備\n", totalCount)
}

// 主函數
func main() {
    // 創建Ping掃描器
    scanner := PingScanner{
        workers: 50,                        // 並發數為50
        timeout: 500 * time.Millisecond,    // 超時時間為500毫秒
        results: make(map[string][]string), // 結果存儲
    }
    // 獲取本地IP地址
    if err := scanner.getLocalIPs(); err != nil {
        fmt.Println(err)
        return
    }
    // 打印網卡信息
    fmt.Printf("發現 %d 個網卡接口\n", len(scanner.networks))
    for i, network := range scanner.networks {
        fmt.Printf("[%d] 接口名稱: %s, IP: %s (網段: %s.0/24), 狀態: %s\n", i+1, network.Name, network.IP, network.Network, network.Status)
    }
    // 掃描網絡
    ctx := context.Background()
    for _, network := range scanner.networks {
        fmt.Printf("\n開始掃描網段 %s.0/24\n", network.Network)
        fmt.Println("正在掃描,請稍候...")
        scanner.scanNetwork(ctx, network)
    }
    // 打印掃描結果
    scanner.printResults()
    // 等待用戶輸入
    fmt.Println("\n按任意鍵退出...")
    var input string
    fmt.Scanln(&input)
}

下載

源碼:PingAll_code.7z
程序 Windows_x64:PingAll_win_amd64.7z
程序 Linux_amd64:PingAll_linux_amd64.7z



評論已關閉

Top