快速 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