gitee.com/sy_183/go-common@v1.0.5-0.20231205030221-958cfe129b47/utils/net/alloc-port_linux.go (about) 1 package netUtils 2 3 import ( 4 "fmt" 5 "io" 6 "net" 7 "syscall" 8 ) 9 10 type fdSocket int 11 12 func (s fdSocket) Close() error { 13 return syscall.Close(int(s)) 14 } 15 16 func AllocPort(network string, ip net.IP) (socket io.Closer, port int, err error) { 17 switch network { 18 case "tcp", "tcp4", "tcp6": 19 case "udp", "udp4", "udp6": 20 default: 21 return nil, 0, &net.OpError{Op: "dial", Net: network, Source: ipToAddr(ip), Addr: ipToAddr(ip), Err: net.UnknownNetworkError(network)} 22 } 23 var sockaddr syscall.Sockaddr 24 retry: 25 switch len(ip) { 26 case 0: 27 switch network { 28 case "tcp", "tcp4", "udp", "udp4": 29 sockaddr = &syscall.SockaddrInet4{} 30 case "tcp6", "udp6": 31 sockaddr = &syscall.SockaddrInet6{} 32 } 33 case net.IPv4len: 34 if network == "tcp6" || network == "udp6" { 35 ip = ip.To16() 36 goto retry 37 } 38 sockaddrInet4 := &syscall.SockaddrInet4{} 39 copy(sockaddrInet4.Addr[:], ip) 40 sockaddr = sockaddrInet4 41 case net.IPv6len: 42 if network == "tcp4" || network == "udp4" { 43 ipv4 := ip.To4() 44 if ipv4 == nil { 45 return nil, 0, &net.AddrError{Err: "错误的IPV4地址", Addr: ip.String()} 46 } 47 ip = ipv4 48 goto retry 49 } 50 sockaddrInet6 := &syscall.SockaddrInet6{} 51 copy(sockaddrInet6.Addr[:], ip) 52 sockaddr = sockaddrInet6 53 default: 54 return nil, 0, &net.AddrError{Err: "错误的IP地址", Addr: ip.String()} 55 } 56 57 var fd int 58 switch network[:3] { 59 case "tcp": 60 fd, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) 61 case "udp": 62 fd, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) 63 } 64 if err != nil { 65 return nil, 0, err 66 } 67 defer func() { 68 if err != nil { 69 syscall.Close(fd) 70 } 71 }() 72 73 if err = syscall.Bind(fd, sockaddr); err != nil { 74 return nil, 0, err 75 } 76 77 sockaddr, err = syscall.Getsockname(fd) 78 if err != nil { 79 return nil, 0, err 80 } 81 82 switch sa := sockaddr.(type) { 83 case *syscall.SockaddrInet4: 84 return fdSocket(fd), sa.Port, nil 85 case *syscall.SockaddrInet6: 86 return fdSocket(fd), sa.Port, nil 87 default: 88 return nil, 0, &net.AddrError{Err: "无效的sockaddr类型", Addr: fmt.Sprint(sa)} 89 } 90 }