github.com/rolandhe/saber@v0.0.4/nfour/common.go (about)

     1  // tcp network framework
     2  //
     3  // Copyright 2023 The saber Authors. All rights reserved.
     4  
     5  // Package nfour, tcp 网路工具框架,因为 tcp工作在4层上,所以该包命名为 nfour。包含:
     6  //
     7  // 1. 多路复用网络模型实现
     8  //
     9  // 2. 单路复用网络模型实现,即 同步request/response模型
    10  //
    11  // 3. 基于多路复用的rpc框架
    12  //
    13  // 4. json encode的多路复用rpc框架
    14  package nfour
    15  
    16  import (
    17  	"errors"
    18  	"github.com/rolandhe/saber/gocc"
    19  	"io"
    20  	"net"
    21  	"os"
    22  	"time"
    23  )
    24  
    25  const (
    26  	// PayLoadLenBufLength header中的首4个字节,用于记录header后面数据负载的长度
    27  	// header格式:4个字节 + 8个字节 + n个字节的payload, 其中首4个字节里存储 n,8个字节表示request id, 最后的n个字节表示request 数据
    28  	PayLoadLenBufLength = 4
    29  )
    30  
    31  var (
    32  	// PeerCloseError 连接的另一头已经关闭连接
    33  	PeerCloseError = errors.New("peer closed")
    34  	// ExceedConcurrentError 当前的请求已经超出设定的最大并发数
    35  	ExceedConcurrentError = errors.New("exceed concurrent")
    36  	defaultSemaWaitTime   = time.Millisecond
    37  )
    38  
    39  // Task 描述一个请求的数据, 这个请求会被封装成Task 交于任务执行器执行
    40  type Task struct {
    41  	// Payload 请求数据,二进制格式,可以被上层业务解析
    42  	PayLoad []byte
    43  }
    44  
    45  // WorkingFunc 请求的处理函数,请求数据会被解析,执行业务逻辑,生成业务结果,业务结果被转换成二进制格式返回
    46  type WorkingFunc func(task *Task) ([]byte, error)
    47  
    48  // HandleError 请求在处理过程中可能发生err, HandleError 描述一个err应该被转换成哪种返回结果
    49  type HandleError func(err error) []byte
    50  
    51  // NewSrvConf 构建server段的配置
    52  // concurrent 服务的最大并发数, 当到达最大并发后,当前请求等待执行的缺省超时时间是 1 毫秒
    53  func NewSrvConf(working WorkingFunc, errHandle HandleError, concurrent uint) *SrvConf {
    54  	return &SrvConf{
    55  		working,
    56  		errHandle,
    57  		time.Millisecond * 2000,
    58  		time.Millisecond * 2000,
    59  		time.Minute * 10,
    60  		defaultSemaWaitTime,
    61  		gocc.NewDefaultSemaphore(concurrent),
    62  	}
    63  }
    64  
    65  // NewSrvConfSemaWait 构建server段的配置
    66  //
    67  // concurrent 服务的最大并发数, 当到达最大并发后,当前请求等待执行的超时时间由 semaWaitTime 指定
    68  //
    69  // semaWaitTime 当到达最大并发后,当前请求等待执行的超时时间
    70  func NewSrvConfSemaWait(working WorkingFunc, errHandle HandleError, concurrent uint, semaWaitTime time.Duration) *SrvConf {
    71  	if semaWaitTime < 0 {
    72  		semaWaitTime = defaultSemaWaitTime
    73  	}
    74  	return &SrvConf{
    75  		working,
    76  		errHandle,
    77  		time.Millisecond * 2000,
    78  		time.Millisecond * 2000,
    79  		time.Minute * 10,
    80  		semaWaitTime,
    81  		gocc.NewDefaultSemaphore(concurrent),
    82  	}
    83  }
    84  
    85  // SrvConf 描述服务端的配置, 包括:
    86  //
    87  //	Working 请求处理函数
    88  //
    89  // # ErrHandle 出错信息出来
    90  //
    91  // SemaWaitTime 如果当前已经到达最大并发,当前请求等待被执行的超时时间
    92  type SrvConf struct {
    93  	Working      WorkingFunc
    94  	ErrHandle    HandleError
    95  	ReadTimeout  time.Duration
    96  	WriteTimeout time.Duration
    97  	IdleTimeout  time.Duration
    98  	SemaWaitTime time.Duration
    99  	concurrent   gocc.Semaphore
   100  }
   101  
   102  // GetConcurrent 获取当前服务配置的最大并发数的信号量
   103  func (conf *SrvConf) GetConcurrent() gocc.Semaphore {
   104  	return conf.concurrent
   105  }
   106  
   107  // InternalReadPayload 从连接中读取指定长度的数据, 主要是内部使用
   108  // notHalt 当长时间读取不到数据且收到超时异常时,是不是不中断连接,true,不中断连接,继续读取
   109  func InternalReadPayload(conn net.Conn, buff []byte, expectLen int, notHalt bool) error {
   110  	l := 0
   111  	for {
   112  		n, err := conn.Read(buff)
   113  		if err != nil {
   114  			if !notHalt && errors.Is(err, os.ErrDeadlineExceeded) {
   115  				NFourLogger.InfoLn(err, l)
   116  				return err
   117  			}
   118  			if errors.Is(err, io.EOF) {
   119  				NFourLogger.InfoLn("peer closed")
   120  				return PeerCloseError
   121  			}
   122  			return err
   123  		}
   124  		l += n
   125  
   126  		if l == expectLen {
   127  			break
   128  		}
   129  		buff = buff[n:]
   130  	}
   131  	return nil
   132  }