2019-02-02 16:18:25 +08:00
|
|
|
|
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
2018-07-18 11:43:30 +08:00
|
|
|
|
//
|
|
|
|
|
// 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,
|
2019-02-02 16:18:25 +08:00
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2018-07-18 11:43:30 +08:00
|
|
|
|
|
|
|
|
|
package gtcp
|
|
|
|
|
|
|
|
|
|
import (
|
2019-06-04 23:33:46 +08:00
|
|
|
|
"crypto/rand"
|
|
|
|
|
"crypto/tls"
|
|
|
|
|
"net"
|
|
|
|
|
"time"
|
2019-07-29 21:01:19 +08:00
|
|
|
|
|
|
|
|
|
"github.com/gogf/gf/os/gfile"
|
2018-07-18 11:43:30 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
2019-06-19 09:06:52 +08:00
|
|
|
|
gDEFAULT_RETRY_INTERVAL = 100 // (毫秒)默认重试时间间隔
|
|
|
|
|
gDEFAULT_READ_BUFFER_SIZE = 128 // (byte)默认数据读取缓冲区大小
|
2018-07-18 11:43:30 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Retry struct {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
Count int // 重试次数
|
|
|
|
|
Interval int // 重试间隔(毫秒)
|
2018-07-18 11:43:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-04 23:33:46 +08:00
|
|
|
|
// Deprecated.
|
2018-07-18 11:43:30 +08:00
|
|
|
|
// 常见的二进制数据校验方式,生成校验结果
|
|
|
|
|
func Checksum(buffer []byte) uint32 {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
var checksum uint32
|
|
|
|
|
for _, b := range buffer {
|
|
|
|
|
checksum += uint32(b)
|
|
|
|
|
}
|
|
|
|
|
return checksum
|
2018-07-18 11:43:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建原生TCP链接, addr地址格式形如:127.0.0.1:80
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func NewNetConn(addr string, timeout ...int) (net.Conn, error) {
|
|
|
|
|
if len(timeout) > 0 {
|
|
|
|
|
return net.DialTimeout("tcp", addr, time.Duration(timeout[0])*time.Millisecond)
|
|
|
|
|
} else {
|
|
|
|
|
return net.Dial("tcp", addr)
|
|
|
|
|
}
|
2018-07-18 11:43:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-04 23:33:46 +08:00
|
|
|
|
// 创建支持TLS的原生TCP链接, addr地址格式形如:127.0.0.1:80
|
|
|
|
|
func NewNetConnTLS(addr string, tlsConfig *tls.Config) (net.Conn, error) {
|
|
|
|
|
return tls.Dial("tcp", addr, tlsConfig)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据给定的证书和密钥文件创建支持TLS的原生TCP链接, addr地址格式形如:127.0.0.1:80
|
|
|
|
|
func NewNetConnKeyCrt(addr, crtFile, keyFile string) (net.Conn, error) {
|
|
|
|
|
tlsConfig, err := LoadKeyCrt(crtFile, keyFile)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return NewNetConnTLS(addr, tlsConfig)
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-18 11:43:30 +08:00
|
|
|
|
// (面向短链接)发送数据
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func Send(addr string, data []byte, retry ...Retry) error {
|
|
|
|
|
conn, err := NewConn(addr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
defer conn.Close()
|
|
|
|
|
return conn.Send(data, retry...)
|
2018-07-18 11:43:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// (面向短链接)发送数据并等待接收返回数据
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func SendRecv(addr string, data []byte, receive int, retry ...Retry) ([]byte, error) {
|
2019-04-28 23:55:23 +08:00
|
|
|
|
conn, err := NewConn(addr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defer conn.Close()
|
|
|
|
|
return conn.SendRecv(data, receive, retry...)
|
2018-07-18 11:43:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// (面向短链接)带超时时间的数据发送
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func SendWithTimeout(addr string, data []byte, timeout time.Duration, retry ...Retry) error {
|
|
|
|
|
conn, err := NewConn(addr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
defer conn.Close()
|
|
|
|
|
return conn.SendWithTimeout(data, timeout, retry...)
|
2018-07-18 11:43:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// (面向短链接)发送数据并等待接收返回数据(带返回超时等待时间)
|
2019-06-19 09:06:52 +08:00
|
|
|
|
func SendRecvWithTimeout(addr string, data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error) {
|
|
|
|
|
conn, err := NewConn(addr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defer conn.Close()
|
|
|
|
|
return conn.SendRecvWithTimeout(data, receive, timeout, retry...)
|
2018-07-18 11:43:30 +08:00
|
|
|
|
}
|
2018-08-06 21:19:48 +08:00
|
|
|
|
|
|
|
|
|
// 判断是否是超时错误
|
|
|
|
|
func isTimeout(err error) bool {
|
2019-06-19 09:06:52 +08:00
|
|
|
|
if err == nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
2019-06-04 23:33:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据证书和密钥生成TLS对象
|
|
|
|
|
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, err
|
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
|
tlsConfig := &tls.Config{}
|
2019-06-04 23:33:46 +08:00
|
|
|
|
tlsConfig.Certificates = []tls.Certificate{crt}
|
2019-06-19 09:06:52 +08:00
|
|
|
|
tlsConfig.Time = time.Now
|
|
|
|
|
tlsConfig.Rand = rand.Reader
|
2019-06-04 23:33:46 +08:00
|
|
|
|
return tlsConfig, nil
|
2019-06-19 09:06:52 +08:00
|
|
|
|
}
|