【问题标题】:syscall.Sockaddr Type Assertionsyscall.Sockaddr 类型断言
【发布时间】:2014-09-03 23:02:09
【问题描述】:

我正在打开一个 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。当Recvmsg 尝试执行分配时,尝试将我的msg 结构成员更改为该类型失败,因为它不是syscall.Sockaddr 类型。

我能够使用类型断言:

bar := pkt.from.(*syscall.SockaddrLinklayer)
fmt.Println(bar.Ifindex)

>>> 2

我对 Go 很陌生;这是我的第一个静态类型语言,所以我不明白 Recvmsg 函数是如何要求 syscall.Sockaddr 返回 *syscall.SockaddrLinklayer?我显然错过了一些非常基本的东西。另外,使用类型断言是正确的方法吗?感觉不太对劲……但我真的没有资格做出这样的判断!

【问题讨论】:

    标签: linux sockets go type-assertion


    【解决方案1】:

    Sockaddr 是一个接口,因此Recvmsg 可以返回满足该接口的不同类型。

    有关接口的更多详细信息,请查看Effective Go

    您应该检查断言是否有效,这样您就不会遇到运行时错误,例如:

    bar, ok := pkt.from.(*syscall.SockaddrLinklayer) 
    if !ok {
        //log error and break out of the loop
    }
    stuffWith(bar)
    

    【讨论】:

    • 好吧——说得通。使用类型断言是读取这些数据的“正确”方式吗?
    • @tMC 是的,但你必须确保它是有效的,我添加了一个小例子。
    猜你喜欢
    • 2014-01-22
    • 1970-01-01
    • 2018-11-19
    • 2020-03-13
    • 2019-08-31
    • 1970-01-01
    • 2019-08-21
    • 2019-01-01
    • 2019-11-03
    相关资源
    最近更新 更多