英文:
syscall.Sockaddr Type Assertion
问题
我正在打开一个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结构体成员,我可以看到Sockaddr接口中的值:
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
我对Go语言非常陌生;这是我第一次接触静态类型语言,所以我不理解为什么Recvmsg函数要求一个syscall.Sockaddr类型,但返回一个*syscall.SockaddrLinklayer类型?我显然漏掉了一些非常基本的东西。另外,使用类型断言的方式是否正确?它感觉不太对...但我没有资格做出这样的判断!
英文:
I am opening a Linux packet socket and trying to read received packets into a struct:
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)
Per the documentation (http://golang.org/pkg/syscall/#Recvmsg) Recvmsg() returns the msghdr as a syscall.Sockaddr and the code pieces I've outlined above works.
Printing out the pkt.from struct member, I can see the values in the 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]}}
However, if I try to access them, I get an error:
fmt.Println(pkt.from.Ifindex)
>>> pkt.from.Ifindex undefined (type syscall.Sockaddr has no field or method Ifindex)
Via reflect.TypeOf(pkt.from) I found it was of type *syscall.SockaddrLinklayer. Trying to change my msg struct member to that type fails when Recvmsg tries to do the assignment since it not of type syscall.Sockaddr.
I was able to use a type assertion:
bar := pkt.from.(*syscall.SockaddrLinklayer)
fmt.Println(bar.Ifindex)
>>> 2
I'm very new to Go; it is my first statically typed language so I don't understand how the Recvmsg func is requiring a syscall.Sockaddr but returning a *syscall.SockaddrLinklayer? I'm clearly missing something very fundamental. Also, is using the type assertion the correct way to do this? It doesn't really feel right... but I'm not really qualified to make such judgments!
答案1
得分: 3
Sockaddr是一个接口,因此Recvmsg可以返回满足该接口的不同类型。
有关接口的更多详细信息,请查看Effective Go。
你应该检查断言是否有效,这样就不会出现运行时错误,例如:
bar, ok := pkt.from.(*syscall.SockaddrLinklayer)
if !ok {
//记录错误并跳出循环
}
使用bar进行操作
英文:
Sockaddr is an interface, so Recvmsg can return different types that fulfill that interface.
For more details about interfaces check Effective Go.
You should check if the assertion is valid or not so you wouldn't end up with a runtime error, for example:
bar, ok := pkt.from.(*syscall.SockaddrLinklayer)
if !ok {
//log error and break out of the loop
}
stuffWith(bar)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论