gtcp_func.go 6.6 KB

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