英文:
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论