从Windows上的Go *net.UDPConn获取syscall.Handle?

huangapple go评论81阅读模式
英文:

Get syscall.Handle from a Go *net.UDPConn on Windows?

问题

我如何在Windows上获取*net.UDPConn的底层syscall.Handle?我想要使用这个句柄通过syscall.SetsockoptInt来设置IP_MULTICAST_TTL。在Linux上,我会这样做:

func setTTL(conn *net.UDPConn, ttl int) error {
    f, err := conn.File()
    if err != nil {
        return err
    }
    defer f.Close()
    fd := int(f.Fd())
    return syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_MULTICAST_TTL, ttl)
}

但是在Windows上,*net.UDPConnFile()内部的隐式dup失败,报错为:

>04:24:49 main.go:150: dup: not supported by windows

并且在源代码中被标记为待办事项。我如何获取这个句柄?如果不能获取,是否有其他设置TTL的方法?

更新0

我已经将这些问题提交到Go问题跟踪器:

英文:

How do I obtain the underlying syscall.Handle for a *net.UDPConn on Windows? I want this handle to set the IP_MULTICAST_TTL via syscall.SetsockoptInt. On Linux I do the following:

func setTTL(conn *net.UDPConn, ttl int) error {
    f, err := conn.File()
    if err != nil {
        return err
    }
    defer f.Close()
    fd := int(f.Fd())
    return syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_MULTICAST_TTL, ttl)
}

But on Windows, the implicit dup inside *net.UDPConn's File() fails with:

>04:24:49 main.go:150: dup: not supported by windows

And in the source code is marked as a to-do. How can I get this handle? Is there some other way to set the TTL if not?

Update0

I've submitted the shortcomings to the Go issue tracker:

答案1

得分: 12

正确的方法是:

  1. 为Windows实现dup()函数。
  2. 提交给Go作为一个变更集。
  3. 等待发布后再使用。

显然,正确的方法存在一些问题...但我强烈建议这样做。Go需要Windows开发人员来解决这些严重问题。在Windows上无法实现这个功能的唯一原因是没有人实现这个函数。

错误的方法是:

在你编写的补丁被接受和发布之前,你可以通过使用unsafe来模拟它。以下代码的工作原理是通过镜像一个net.UDPConn的确切结构来实现。这包括复制构成UDPConn的所有来自net的结构体。然后使用unsafe来断言本地的UDPConn与net的UDPConn相同。编译器无法检查这一点,并相信你的说法。如果net的内部发生了变化,它仍然可以编译,但是不知道会发生什么。

所有代码都未经测试。

package reallyunsafenet

import (
        "net"
        "sync"
        "syscall"
        "unsafe"
)

// 从go/src/pkg/net/fd_windows.go复制
type ioResult struct {
        qty uint32
        err error
}

// 从go/src/pkg/net/fd_windows.go复制
type netFD struct {
        // sysfd的锁定/生命周期
        sysmu   sync.Mutex
        sysref  int
        closing bool

        // 在关闭之前不可变
        sysfd       syscall.Handle
        family      int
        sotype      int
        isConnected bool
        net         string
        laddr       net.Addr
        raddr       net.Addr
        resultc     [2]chan ioResult
        errnoc      [2]chan error

        // 由客户端拥有
        rdeadline int64
        rio       sync.Mutex
        wdeadline int64
        wio       sync.Mutex
}

// 从go/src/pkg/net/udpsock_posix.go复制
type UDPConn struct {
    fd *netFD
}

// 获取fd的函数
func GetFD(conn *net.UDPConn) syscall.Handle {
        c := (*UDPConn)(unsafe.Pointer(conn))
        return c.fd.sysfd
}
英文:

The short answer is impossible. But since that isn't an answer you want to hear, I will give you the right way and wrong way to solve the problem.

The right way:

  1. implement dup() for Windows.
  2. submit to Go as a changeset
  3. wait for it to be released to use it

Obviously the right way has some issues... but I highly recommend doing it. Go needs windows developers to fix up these types of serious problems. The only reason this can't be done in Windows is no one implemented the function

The wrong way:

Until the patch you write gets accepted and released, you can fake it through unsafe. The way the following code works by mirroring the exact structure of a net.UDPConn. This included copying over all structs from net that make up a UDPConn. Then unsafe is used to assert that the local UDPConn is the same as net's UDPConn. The compiler can not check this and takes your word for it. Were the internals of net to ever change, it would compile but god knows what it would do.

All code is untested.

package reallyunsafenet

import (
        "net"
        "sync"
        "syscall"
        "unsafe"
)

// copied from go/src/pkg/net/fd_windows.go
type ioResult struct {
        qty uint32
        err error
}

// copied from go/src/pkg/net/fd_windows.go
type netFD struct {
        // locking/lifetime of sysfd
        sysmu   sync.Mutex
        sysref  int
        closing bool

        // immutable until Close
        sysfd       syscall.Handle
        family      int
        sotype      int
        isConnected bool
        net         string
        laddr       net.Addr
        raddr       net.Addr
        resultc     [2]chan ioResult
        errnoc      [2]chan error

        // owned by client
        rdeadline int64
        rio       sync.Mutex
        wdeadline int64
        wio       sync.Mutex
}

// copied from go/src/pkg/net/udpsock_posix.go
type UDPConn struct {
    fd *netFD
}

// function to get fd
func GetFD(conn *net.UDPConn) syscall.Handle {
        c := (*UDPConn)(unsafe.Pointer(conn))
        return c.fd.sysfd
}

huangapple
  • 本文由 发表于 2012年7月4日 04:55:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/11319025.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定