简介
Go库中很多实现的arp都是支持osx/linux/bsd之类的, 但几乎没有支持windows的, 也试了一些方式,
目前还是选用调用windows的API, 记录一下这一次windows的API的调用经验。
实现
代码
package main
/*
#cgo CFLAGS: -I.
#cgo LDFLAGS: -liphlpapi -lws2_32
#include <winsock2.h>
#include <windows.h>
#include <iphlpapi.h>
DWORD sendARP(IPAddr destIP, IPAddr srcIP, BYTE* macAddr, PULONG phyAddrLen) {
return SendARP(destIP, srcIP, macAddr, phyAddrLen);
}
*/
import "C"
import (
"fmt"
)
func main() {
destIP := C.inet_addr(C.CString("192.168.3.2")) // 目标IP地址
var srcIP C.IPAddr = C.INADDR_ANY // 源IP地址,使用INADDR_ANY表示任意本地地址
var macAddr [6]C.BYTE
phyAddrLen := C.ULONG(6)
result := C.sendARP(destIP, srcIP, &macAddr[0], &phyAddrLen)
if result == C.NO_ERROR {
mac := fmt.Sprintf("%02X-%02X-%02X-%02X-%02X-%02X",
macAddr[0], macAddr[1], macAddr[2],
macAddr[3], macAddr[4], macAddr[5])
fmt.Println("MAC address:", mac)
} else {
switch result {
case C.ERROR_GEN_FAILURE:
fmt.Printf(" (ERROR_GEN_FAILURE)\n")
break
case C.ERROR_INVALID_PARAMETER:
fmt.Printf(" (ERROR_INVALID_PARAMETER)\n")
break
case C.ERROR_INVALID_USER_BUFFER:
fmt.Printf(" (ERROR_INVALID_USER_BUFFER)\n")
break
case C.ERROR_BAD_NET_NAME:
fmt.Printf(" (ERROR_GEN_FAILURE)\n")
break
case C.ERROR_BUFFER_OVERFLOW:
fmt.Printf(" (ERROR_BUFFER_OVERFLOW)\n")
break
case C.ERROR_NOT_FOUND:
fmt.Printf(" (ERROR_NOT_FOUND)\n")
break
default:
fmt.Printf("\n")
break
}
fmt.Println("SendARP failed with error code:", result)
}
}
注意点
-
启用CGO
CGO_ENABLED=1 -
设置gcc、g++
例如我将Qt的编译组件 加到环境变量中,记住自己系统或者配置的cpu选择gcc\g++ 我设置的环境变量是-> D:\Softwares\IDEs\Qt\Tools\mingw810_64\bin -
头文件先后错误问题
#include <winsock2.h>
#include <windows.h>
#include <iphlpapi.h>
在cgo标志里面包含这些头文件, winsock2.h必须在前, 否则报错。
- 包装器方式解决类型问题
#include <winsock2.h>
#include <windows.h>
#include <iphlpapi.h>
DWORD sendARP(IPAddr destIP, IPAddr srcIP, BYTE* macAddr, PULONG phyAddrLen) {
return SendARP(destIP, srcIP, macAddr, phyAddrLen);
}
如果直接调用SendARP会报类型错误的问题, 所以这里需要先包装器一层, 确定表层转化类型。
- 明确类型
对的
var srcIP C.IPAddr = C.INADDR_ANY // 源IP地址,使用INADDR_ANY表示任意本地地址
下面 错误, 使用时报类型错误问题
var srcIP = C.INADDR_ANY // 源IP地址,使用INADDR_ANY表示任意本地地址
其余参考官方接口提供的示例, 改成go的即可…
参考
sendARP 函数 (iphlpapi.h)