源代码地址:
https://github.com/tongxinCode/mping.git
该项目有幸列入2020北极代码保险库。
核心内容:
socket编程
组播技术
多网卡
注意事项:
1.Golang自带的net库实现不了任意源和指定源,要使用“golang.org/x/net/ipv4”
详情见https://godoc.org/golang.org/x/net/ipv4
2.Windows上指定源接收异常,这是由于“golang.org/x/net/ipv4”库Windows部分
未完成,Linux x86和Linux arm均正常
文件目录
.
├── build
├── LICENSE
├── main.go
├── mping
├── multicast
│ ├── broadcaster.go
│ └── listener.go
└── README.md
难点解析:
1.socket编程
对于发包而言构造包相对较麻烦,构造出相对完整的数据包结构体是必要的:
type Packet struct {
TTL int
Port int
Address net.IP
RouterAlert bool
Raw bool
IGMPVersion int // 1, 2, or 3
Interface *net.Interface
Message []byte
Protocol string // 'udp' or 'ip:2'/'ip4:2'
TargetAddr *net.UDPAddr
LocalAddress *net.UDPAddr
udpConn *net.UDPConn
packetConn *ipv4.PacketConn
ipConn net.PacketConn
rawConn *ipv4.RawConn
padding []byte
TOS int
}
2.组播技术
对于收包而言,组播收发要分为指定源和任意源两个部分进行实现,每个部分分为
加入和离开两个函数,每个函数要调用相应的syscall(这部分golang.org/x/net
/ipv4已经封装好了),最后针对两个部分做一层封装。
3.多网卡
Linux设备上实体网卡、虚拟网卡、bridge、loopback多重多样,调用正确的网卡
十分关键,这里不推荐使用网卡名称、mac地址过滤网卡设备,尽量选取ip地址作
过滤。
func getifi(addr string) (*net.Interface, error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
if host == "127.0.0.1" {
return nil, nil
}
netInterfaces, err := net.Interfaces()
if err != nil {
return nil, err
}
for i := 0; i < len(netInterfaces); i++ {
if (netInterfaces[i].Flags & net.FlagUp) != 0 {
addrs, _ := netInterfaces[i].Addrs()
for _, address := range addrs {
ipv4 := ipReg.FindString(address.String())
if ipv4 == host {
ifi := &netInterfaces[i]
}
return ifi, nil
}
}
}
}
return nil, nil
}
此外,该项目还使用了flag库进行了help指令提示的编写,使用log库进行了日志模块的编写,编译的二进制文件可用性较高。
联系客服