Fork me on GitHub

有关 file udp not supported by windows 的问题

  1. func createUDPConn(device *Device, raddr *net.UDPAddr) (int, error) {
  2. netc := &device.net
  3. netc.mutex.Lock()
  4. defer netc.mutex.Unlock()
  5. // close existing connection
  6. if netc.conn != nil {
  7. logger.Wlog.SaveInfoLog("断开旧的udp连接:" + netc.conn.LocalAddr().String())
  8. go netc.conn.Close()
  9. netc.conn = nil
  10. }
  11. // open new connection
  12. // listen on new address
  13. conn, err := net.DialUDP("udp", nil, raddr)
  14. if err != nil {
  15. return -1, err
  16. }
  17. setMark(conn, uint32(fwmarkIoctl))
  18. netc.conn = conn
  19. logger.Wlog.SaveInfoLog("创建新的udp连接:" + conn.LocalAddr().String())
  20. // notify goroutines
  21. signalSend(device.signal.newUDPConn)
  22. f, err := conn.File()
  23. if err != nil {
  24. return -1, err
  25. }
  26. return int(f.Fd()), nil
  27. }

上面这段代码在 linux 平台运行没啥问题,但是在 windows 平台就会提示 file udp not supported by windows

有关解决方法,我看到一个挺不错的回答,记录分享一下:

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:

implement dup() for Windows.
submit to Go as a changeset
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.

  1. package reallyunsafenet
  2. import (
  3. "net"
  4. "sync"
  5. "syscall"
  6. "unsafe"
  7. )
  8. // copied from go/src/pkg/net/fd_windows.go
  9. type ioResult struct {
  10. qty uint32
  11. err error
  12. }
  13. // copied from go/src/pkg/net/fd_windows.go
  14. type netFD struct {
  15. // locking/lifetime of sysfd
  16. sysmu sync.Mutex
  17. sysref int
  18. closing bool
  19. // immutable until Close
  20. sysfd syscall.Handle
  21. family int
  22. sotype int
  23. isConnected bool
  24. net string
  25. laddr net.Addr
  26. raddr net.Addr
  27. resultc [2]chan ioResult
  28. errnoc [2]chan error
  29. // owned by client
  30. rdeadline int64
  31. rio sync.Mutex
  32. wdeadline int64
  33. wio sync.Mutex
  34. }
  35. // copied from go/src/pkg/net/udpsock_posix.go
  36. type UDPConn struct {
  37. fd *netFD
  38. }
  39. // function to get fd
  40. func GetFD(conn *net.UDPConn) syscall.Handle {
  41. c := (*UDPConn)(unsafe.Pointer(conn))
  42. return c.fd.sysfd
  43. }

—————————— 补充一下 ———————————

可能是这份代码太老了,net包的有些函数已经改了,我补充一下:

  1. package controller
  2. import (
  3. "golang.org/x/sys/windows"
  4. "net"
  5. "sync"
  6. "syscall"
  7. "unsafe"
  8. )
  9. // copied from go/src/pkg/net/fd_windows.go
  10. type ioResult struct {
  11. qty uint32
  12. err error
  13. }
  14. type FD struct {
  15. // Lock sysfd and serialize access to Read and Write methods.
  16. fdmu fdMutex
  17. // System file descriptor. Immutable until Close.
  18. Sysfd syscall.Handle
  19. // Read operation.
  20. rop operation
  21. // Write operation.
  22. wop operation
  23. // I/O poller.
  24. pd pollDesc
  25. // Used to implement pread/pwrite.
  26. l sync.Mutex
  27. // For console I/O.
  28. lastbits []byte // first few bytes of the last incomplete rune in last write
  29. readuint16 []uint16 // buffer to hold uint16s obtained with ReadConsole
  30. readbyte []byte // buffer to hold decoding of readuint16 from utf16 to utf8
  31. readbyteOffset int // readbyte[readOffset:] is yet to be consumed with file.Read
  32. // Semaphore signaled when file is closed.
  33. csema uint32
  34. skipSyncNotif bool
  35. // Whether this is a streaming descriptor, as opposed to a
  36. // packet-based descriptor like a UDP socket.
  37. IsStream bool
  38. // Whether a zero byte read indicates EOF. This is false for a
  39. // message based socket connection.
  40. ZeroReadIsEOF bool
  41. // Whether this is a file rather than a network socket.
  42. isFile bool
  43. // The kind of this file.
  44. kind fileKind
  45. }
  46. // copied from go/src/pkg/net/fd_windows.go
  47. type netFD struct {
  48. pfd FD
  49. // immutable until Close
  50. family int
  51. sotype int
  52. isConnected bool // handshake completed or use of association with peer
  53. net string
  54. laddr net.Addr
  55. raddr net.Addr
  56. }
  57. // copied from go/src/pkg/net/udpsock_posix.go
  58. type UDPConn struct {
  59. fd *netFD
  60. }
  61. type fdMutex struct {
  62. state uint64
  63. rsema uint32
  64. wsema uint32
  65. }
  66. type operation struct {
  67. // Used by IOCP interface, it must be first field
  68. // of the struct, as our code rely on it.
  69. o syscall.Overlapped
  70. // fields used by runtime.netpoll
  71. runtimeCtx uintptr
  72. mode int32
  73. errno int32
  74. qty uint32
  75. // fields used only by net package
  76. fd *FD
  77. errc chan error
  78. buf syscall.WSABuf
  79. msg windows.WSAMsg
  80. sa syscall.Sockaddr
  81. rsa *syscall.RawSockaddrAny
  82. rsan int32
  83. handle syscall.Handle
  84. flags uint32
  85. bufs []syscall.WSABuf
  86. }
  87. type pollDesc struct {
  88. runtimeCtx uintptr
  89. }
  90. // fileKind describes the kind of file.
  91. type fileKind byte
  92. // function to get fd
  93. func GetFD(conn *net.UDPConn) syscall.Handle {
  94. c := (*UDPConn)(unsafe.Pointer(conn))
  95. return c.fd.pfd.Sysfd
  96. }
2020-06-09 15:52:03  LeeChan 阅读(12) 评论(0) 标签:udp,windows 分类:技术编程