github.com/wangyougui/gf/v2@v2.6.5/net/gtcp/gtcp_func.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package gtcp 8 9 import ( 10 "crypto/rand" 11 "crypto/tls" 12 "net" 13 "time" 14 15 "github.com/wangyougui/gf/v2/errors/gerror" 16 "github.com/wangyougui/gf/v2/os/gfile" 17 ) 18 19 const ( 20 defaultConnTimeout = 30 * time.Second // Default connection timeout. 21 defaultRetryInternal = 100 * time.Millisecond // Default retry interval. 22 defaultReadBufferSize = 128 // (Byte) Buffer size for reading. 23 ) 24 25 type Retry struct { 26 Count int // Retry count. 27 Interval time.Duration // Retry interval. 28 } 29 30 // NewNetConn creates and returns a net.Conn with given address like "127.0.0.1:80". 31 // The optional parameter `timeout` specifies the timeout for dialing connection. 32 func NewNetConn(address string, timeout ...time.Duration) (net.Conn, error) { 33 var ( 34 network = `tcp` 35 duration = defaultConnTimeout 36 ) 37 if len(timeout) > 0 { 38 duration = timeout[0] 39 } 40 conn, err := net.DialTimeout(network, address, duration) 41 if err != nil { 42 err = gerror.Wrapf( 43 err, 44 `net.DialTimeout failed with network "%s", address "%s", timeout "%s"`, 45 network, address, duration, 46 ) 47 } 48 return conn, err 49 } 50 51 // NewNetConnTLS creates and returns a TLS net.Conn with given address like "127.0.0.1:80". 52 // The optional parameter `timeout` specifies the timeout for dialing connection. 53 func NewNetConnTLS(address string, tlsConfig *tls.Config, timeout ...time.Duration) (net.Conn, error) { 54 var ( 55 network = `tcp` 56 dialer = &net.Dialer{ 57 Timeout: defaultConnTimeout, 58 } 59 ) 60 if len(timeout) > 0 { 61 dialer.Timeout = timeout[0] 62 } 63 conn, err := tls.DialWithDialer(dialer, network, address, tlsConfig) 64 if err != nil { 65 err = gerror.Wrapf( 66 err, 67 `tls.DialWithDialer failed with network "%s", address "%s", timeout "%s", tlsConfig "%v"`, 68 network, address, dialer.Timeout, tlsConfig, 69 ) 70 } 71 return conn, err 72 } 73 74 // NewNetConnKeyCrt creates and returns a TLS net.Conn with given TLS certificate and key files 75 // and address like "127.0.0.1:80". The optional parameter `timeout` specifies the timeout for 76 // dialing connection. 77 func NewNetConnKeyCrt(addr, crtFile, keyFile string, timeout ...time.Duration) (net.Conn, error) { 78 tlsConfig, err := LoadKeyCrt(crtFile, keyFile) 79 if err != nil { 80 return nil, err 81 } 82 return NewNetConnTLS(addr, tlsConfig, timeout...) 83 } 84 85 // Send creates connection to `address`, writes `data` to the connection and then closes the connection. 86 // The optional parameter `retry` specifies the retry policy when fails in writing data. 87 func Send(address string, data []byte, retry ...Retry) error { 88 conn, err := NewConn(address) 89 if err != nil { 90 return err 91 } 92 defer conn.Close() 93 return conn.Send(data, retry...) 94 } 95 96 // SendRecv creates connection to `address`, writes `data` to the connection, receives response 97 // and then closes the connection. 98 // 99 // The parameter `length` specifies the bytes count waiting to receive. It receives all buffer content 100 // and returns if `length` is -1. 101 // 102 // The optional parameter `retry` specifies the retry policy when fails in writing data. 103 func SendRecv(address string, data []byte, length int, retry ...Retry) ([]byte, error) { 104 conn, err := NewConn(address) 105 if err != nil { 106 return nil, err 107 } 108 defer conn.Close() 109 return conn.SendRecv(data, length, retry...) 110 } 111 112 // SendWithTimeout does Send logic with writing timeout limitation. 113 func SendWithTimeout(address string, data []byte, timeout time.Duration, retry ...Retry) error { 114 conn, err := NewConn(address) 115 if err != nil { 116 return err 117 } 118 defer conn.Close() 119 return conn.SendWithTimeout(data, timeout, retry...) 120 } 121 122 // SendRecvWithTimeout does SendRecv logic with reading timeout limitation. 123 func SendRecvWithTimeout(address string, data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) { 124 conn, err := NewConn(address) 125 if err != nil { 126 return nil, err 127 } 128 defer conn.Close() 129 return conn.SendRecvWithTimeout(data, receive, timeout, retry...) 130 } 131 132 // isTimeout checks whether given `err` is a timeout error. 133 func isTimeout(err error) bool { 134 if err == nil { 135 return false 136 } 137 if netErr, ok := err.(net.Error); ok && netErr.Timeout() { 138 return true 139 } 140 return false 141 } 142 143 // LoadKeyCrt creates and returns a TLS configuration object with given certificate and key files. 144 func LoadKeyCrt(crtFile, keyFile string) (*tls.Config, error) { 145 crtPath, err := gfile.Search(crtFile) 146 if err != nil { 147 return nil, err 148 } 149 keyPath, err := gfile.Search(keyFile) 150 if err != nil { 151 return nil, err 152 } 153 crt, err := tls.LoadX509KeyPair(crtPath, keyPath) 154 if err != nil { 155 return nil, gerror.Wrapf(err, 156 `tls.LoadX509KeyPair failed for certFile "%s" and keyFile "%s"`, 157 crtPath, keyPath, 158 ) 159 } 160 tlsConfig := &tls.Config{} 161 tlsConfig.Certificates = []tls.Certificate{crt} 162 tlsConfig.Time = time.Now 163 tlsConfig.Rand = rand.Reader 164 return tlsConfig, nil 165 } 166 167 // MustGetFreePort performs as GetFreePort, but it panics is any error occurs. 168 func MustGetFreePort() int { 169 port, err := GetFreePort() 170 if err != nil { 171 panic(err) 172 } 173 return port 174 } 175 176 // GetFreePort retrieves and returns a port that is free. 177 func GetFreePort() (port int, err error) { 178 var ( 179 network = `tcp` 180 address = `:0` 181 ) 182 resolvedAddr, err := net.ResolveTCPAddr(network, address) 183 if err != nil { 184 return 0, gerror.Wrapf( 185 err, 186 `net.ResolveTCPAddr failed for network "%s", address "%s"`, 187 network, address, 188 ) 189 } 190 l, err := net.ListenTCP(network, resolvedAddr) 191 if err != nil { 192 return 0, gerror.Wrapf( 193 err, 194 `net.ListenTCP failed for network "%s", address "%s"`, 195 network, resolvedAddr.String(), 196 ) 197 } 198 port = l.Addr().(*net.TCPAddr).Port 199 if err = l.Close(); err != nil { 200 err = gerror.Wrapf( 201 err, 202 `close listening failed for network "%s", address "%s", port "%d"`, 203 network, resolvedAddr.String(), port, 204 ) 205 } 206 return 207 } 208 209 // GetFreePorts retrieves and returns specified number of ports that are free. 210 func GetFreePorts(count int) (ports []int, err error) { 211 var ( 212 network = `tcp` 213 address = `:0` 214 ) 215 for i := 0; i < count; i++ { 216 resolvedAddr, err := net.ResolveTCPAddr(network, address) 217 if err != nil { 218 return nil, gerror.Wrapf( 219 err, 220 `net.ResolveTCPAddr failed for network "%s", address "%s"`, 221 network, address, 222 ) 223 } 224 l, err := net.ListenTCP(network, resolvedAddr) 225 if err != nil { 226 return nil, gerror.Wrapf( 227 err, 228 `net.ListenTCP failed for network "%s", address "%s"`, 229 network, resolvedAddr.String(), 230 ) 231 } 232 ports = append(ports, l.Addr().(*net.TCPAddr).Port) 233 _ = l.Close() 234 } 235 return ports, nil 236 }