快速 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://www.zgcwkj.com/archives/247.html
轉載聲明:請注明本文章的標題及內容的出處和聲明,謝謝
評論已關閉