123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
- //
- // This Source Code Form is subject to the terms of the MIT License.
- // If a copy of the MIT was not distributed with this file,
- // You can obtain one at https://github.com/gogf/gf.
- package gtcp
- import (
- "crypto/rand"
- "crypto/tls"
- "net"
- "time"
- "github.com/gogf/gf/v2/errors/gerror"
- "github.com/gogf/gf/v2/os/gfile"
- )
- const (
- defaultConnTimeout = 30 * time.Second // Default connection timeout.
- defaultRetryInternal = 100 * time.Millisecond // Default retry interval.
- defaultReadBufferSize = 128 // (Byte) Buffer size for reading.
- )
- type Retry struct {
- Count int // Retry count.
- Interval time.Duration // Retry interval.
- }
- // NewNetConn creates and returns a net.Conn with given address like "127.0.0.1:80".
- // The optional parameter `timeout` specifies the timeout for dialing connection.
- func NewNetConn(address string, timeout ...time.Duration) (net.Conn, error) {
- var (
- network = `tcp`
- duration = defaultConnTimeout
- )
- if len(timeout) > 0 {
- duration = timeout[0]
- }
- conn, err := net.DialTimeout(network, address, duration)
- if err != nil {
- err = gerror.Wrapf(
- err,
- `net.DialTimeout failed with network "%s", address "%s", timeout "%s"`,
- network, address, duration,
- )
- }
- return conn, err
- }
- // NewNetConnTLS creates and returns a TLS net.Conn with given address like "127.0.0.1:80".
- // The optional parameter `timeout` specifies the timeout for dialing connection.
- func NewNetConnTLS(address string, tlsConfig *tls.Config, timeout ...time.Duration) (net.Conn, error) {
- var (
- network = `tcp`
- dialer = &net.Dialer{
- Timeout: defaultConnTimeout,
- }
- )
- if len(timeout) > 0 {
- dialer.Timeout = timeout[0]
- }
- conn, err := tls.DialWithDialer(dialer, network, address, tlsConfig)
- if err != nil {
- err = gerror.Wrapf(
- err,
- `tls.DialWithDialer failed with network "%s", address "%s", timeout "%s", tlsConfig "%v"`,
- network, address, dialer.Timeout, tlsConfig,
- )
- }
- return conn, err
- }
- // NewNetConnKeyCrt creates and returns a TLS net.Conn with given TLS certificate and key files
- // and address like "127.0.0.1:80". The optional parameter `timeout` specifies the timeout for
- // dialing connection.
- func NewNetConnKeyCrt(addr, crtFile, keyFile string, timeout ...time.Duration) (net.Conn, error) {
- tlsConfig, err := LoadKeyCrt(crtFile, keyFile)
- if err != nil {
- return nil, err
- }
- return NewNetConnTLS(addr, tlsConfig, timeout...)
- }
- // Send creates connection to `address`, writes `data` to the connection and then closes the connection.
- // The optional parameter `retry` specifies the retry policy when fails in writing data.
- func Send(address string, data []byte, retry ...Retry) error {
- conn, err := NewConn(address)
- if err != nil {
- return err
- }
- defer conn.Close()
- return conn.Send(data, retry...)
- }
- // SendRecv creates connection to `address`, writes `data` to the connection, receives response
- // and then closes the connection.
- //
- // The parameter `length` specifies the bytes count waiting to receive. It receives all buffer content
- // and returns if `length` is -1.
- //
- // The optional parameter `retry` specifies the retry policy when fails in writing data.
- func SendRecv(address string, data []byte, length int, retry ...Retry) ([]byte, error) {
- conn, err := NewConn(address)
- if err != nil {
- return nil, err
- }
- defer conn.Close()
- return conn.SendRecv(data, length, retry...)
- }
- // SendWithTimeout does Send logic with writing timeout limitation.
- func SendWithTimeout(address string, data []byte, timeout time.Duration, retry ...Retry) error {
- conn, err := NewConn(address)
- if err != nil {
- return err
- }
- defer conn.Close()
- return conn.SendWithTimeout(data, timeout, retry...)
- }
- // SendRecvWithTimeout does SendRecv logic with reading timeout limitation.
- func SendRecvWithTimeout(address string, data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) {
- conn, err := NewConn(address)
- if err != nil {
- return nil, err
- }
- defer conn.Close()
- return conn.SendRecvWithTimeout(data, receive, timeout, retry...)
- }
- // isTimeout checks whether given `err` is a timeout error.
- func isTimeout(err error) bool {
- if err == nil {
- return false
- }
- if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
- return true
- }
- return false
- }
- // LoadKeyCrt creates and returns a TLS configuration object with given certificate and key files.
- func LoadKeyCrt(crtFile, keyFile string) (*tls.Config, error) {
- crtPath, err := gfile.Search(crtFile)
- if err != nil {
- return nil, err
- }
- keyPath, err := gfile.Search(keyFile)
- if err != nil {
- return nil, err
- }
- crt, err := tls.LoadX509KeyPair(crtPath, keyPath)
- if err != nil {
- return nil, gerror.Wrapf(err,
- `tls.LoadX509KeyPair failed for certFile "%s" and keyFile "%s"`,
- crtPath, keyPath,
- )
- }
- tlsConfig := &tls.Config{}
- tlsConfig.Certificates = []tls.Certificate{crt}
- tlsConfig.Time = time.Now
- tlsConfig.Rand = rand.Reader
- return tlsConfig, nil
- }
- // MustGetFreePort performs as GetFreePort, but it panics is any error occurs.
- func MustGetFreePort() int {
- port, err := GetFreePort()
- if err != nil {
- panic(err)
- }
- return port
- }
- // GetFreePort retrieves and returns a port that is free.
- func GetFreePort() (port int, err error) {
- var (
- network = `tcp`
- address = `:0`
- )
- resolvedAddr, err := net.ResolveTCPAddr(network, address)
- if err != nil {
- return 0, gerror.Wrapf(
- err,
- `net.ResolveTCPAddr failed for network "%s", address "%s"`,
- network, address,
- )
- }
- l, err := net.ListenTCP(network, resolvedAddr)
- if err != nil {
- return 0, gerror.Wrapf(
- err,
- `net.ListenTCP failed for network "%s", address "%s"`,
- network, resolvedAddr.String(),
- )
- }
- port = l.Addr().(*net.TCPAddr).Port
- if err = l.Close(); err != nil {
- err = gerror.Wrapf(
- err,
- `close listening failed for network "%s", address "%s", port "%d"`,
- network, resolvedAddr.String(), port,
- )
- }
- return
- }
- // GetFreePorts retrieves and returns specified number of ports that are free.
- func GetFreePorts(count int) (ports []int, err error) {
- var (
- network = `tcp`
- address = `:0`
- )
- for i := 0; i < count; i++ {
- resolvedAddr, err := net.ResolveTCPAddr(network, address)
- if err != nil {
- return nil, gerror.Wrapf(
- err,
- `net.ResolveTCPAddr failed for network "%s", address "%s"`,
- network, address,
- )
- }
- l, err := net.ListenTCP(network, resolvedAddr)
- if err != nil {
- return nil, gerror.Wrapf(
- err,
- `net.ListenTCP failed for network "%s", address "%s"`,
- network, resolvedAddr.String(),
- )
- }
- ports = append(ports, l.Addr().(*net.TCPAddr).Port)
- _ = l.Close()
- }
- return ports, nil
- }
|