快速 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
版权属于:zgcwkj
本文链接:https://zgcwkj.cn/archives/247.html
转载声明:请注明本文章的标题及内容的出处和声明,谢谢