我正在打开Linux数据包套接字,并尝试将接收到的数据包读入结构:
type msg struct {
n, oobn, flags int
p, oob []byte
from syscall.Sockaddr
}
socket, err := syscall.Socket(AF_PACKET, SOCK_RAW, ETH_P_ALL)
pkt := new(msg)
pkt.p = make([]byte, 1500)
pkt.oob = make([]byte, 1500)
pkt.n, pkt.oobn, pkt.flags, pkt.from, _ = syscall.Recvmsg(socket, pkt.p, pkt.oob, 0)
根据文档(http://golang.org/pkg/syscall/#Recvmsg),
Recvmsg()
将msghdr作为syscall.Sockaddr
返回,而我上面概述的代码段也有效。打印出
pkt.from
struct成员,我可以在Sockaddr
接口(interface)中看到这些值:fmt.Printf("%+v\n", pkt.from)
>>> &{Protocol:8 Ifindex:3 Hatype:1 Pkttype:0 Halen:6 Addr:[0 0 36 205 126 213 0 0] raw:{Family:0 Protocol:0 Ifindex:0 Hatype:0 Pkttype:0 Halen:0 Addr:[0 0 0 0 0 0 0 0]}}
但是,如果我尝试访问它们,则会收到错误消息:
fmt.Println(pkt.from.Ifindex)
>>> pkt.from.Ifindex undefined (type syscall.Sockaddr has no field or method Ifindex)
通过
reflect.TypeOf(pkt.from)
我发现它的类型为*syscall.SockaddrLinklayer
。当msg
尝试执行分配时,尝试将我的Recvmsg
结构成员更改为该类型失败,因为它不是syscall.Sockaddr
类型。我能够使用类型断言:
bar := pkt.from.(*syscall.SockaddrLinklayer)
fmt.Println(bar.Ifindex)
>>> 2
我是新手。这是我的第一种静态类型语言,所以我不明白
Recvmsg
函数是是如何要求和syscall.Sockaddr
,但返回*syscall.SockaddrLinklayer
吗?我显然错过了一些非常基本的东西。另外,使用类型断言是执行此操作的正确方法吗?感觉真的不对……但是我没有资格做出这样的判断! 最佳答案
Sockaddr是一个接口(interface),因此Recvmsg
可以返回满足该接口(interface)的不同类型。
有关接口(interface)的更多详细信息,请检查Effective Go。
您应该检查断言是否有效,这样就不会导致运行时错误,例如:
bar, ok := pkt.from.(*syscall.SockaddrLinklayer)
if !ok {
//log error and break out of the loop
}
stuffWith(bar)