github.com/rolandhe/saber@v0.0.4/nfour/simplex/srv.go (about) 1 // rpc abstraction basing nfour 2 // Copyright 2023 The saber Authors. All rights reserved. 3 4 // Package simplex 单路模式的服务端实现,类似于http1.1, 大量客户端但每个客户请求较少的场景。每个连接上request/response是同步模式,每个请求必须得到响应以后才能发送另一个请求。 5 // 用于兼容一些老的场景,因此该模式下没有提供客户端组件。 6 package simplex 7 8 import ( 9 "github.com/rolandhe/saber/nfour" 10 "github.com/rolandhe/saber/utils/bytutil" 11 "net" 12 "strconv" 13 "time" 14 ) 15 16 // Startup 启动一个单路服务端,在单路模式下,每个客户端连接对应服务端由一个goroutine服务,且服务是同步模式,每个请求必须被处理且收到响应后才能发送下一个请求,类似http1.1。 17 // 18 // port 服务监听的端口 19 // conf.concurrent 指定了最大并发数 20 func Startup(port int, conf *nfour.SrvConf) { 21 ln, err := net.Listen("tcp", ":"+strconv.Itoa(port)) 22 if err != nil { 23 // handle error 24 nfour.NFourLogger.InfoLn(err) 25 return 26 } 27 nfour.NFourLogger.Info("listen tcp port %d,and next to accept\n", port) 28 for { 29 conn, err := ln.Accept() 30 if err != nil { 31 // handle error 32 nfour.NFourLogger.InfoLn(err) 33 return 34 } 35 go handleConnection(conn, conf) 36 } 37 } 38 39 func handleConnection(conn net.Conn, conf *nfour.SrvConf) { 40 nfour.NFourLogger.DebugLn("start to read header info...") 41 header := make([]byte, nfour.PayLoadLenBufLength) 42 for { 43 conn.SetReadDeadline(time.Now().Add(conf.IdleTimeout)) 44 err := nfour.InternalReadPayload(conn, header, nfour.PayLoadLenBufLength, true) 45 if err != nil { 46 releaseConn(conn) 47 break 48 } 49 l, _ := bytutil.ToInt32(header[:nfour.PayLoadLenBufLength]) 50 bodyBuff := make([]byte, l, l) 51 conn.SetReadDeadline(time.Now().Add(conf.ReadTimeout)) 52 err = nfour.InternalReadPayload(conn, bodyBuff, int(l), false) 53 if err != nil { 54 releaseConn(conn) 55 break 56 } 57 58 if !conf.GetConcurrent().AcquireTimeout(conf.SemaWaitTime) { 59 if !writeCore(conf.ErrHandle(nfour.ExceedConcurrentError), conn, conf.WriteTimeout) { 60 releaseConn(conn) 61 break 62 } 63 continue 64 } 65 ok := doBiz(bodyBuff, conn, conf) 66 conf.GetConcurrent().Release() 67 if !ok { 68 releaseConn(conn) 69 break 70 } 71 } 72 } 73 74 func doBiz(bodyBuff []byte, conn net.Conn, conf *nfour.SrvConf) bool { 75 task := &nfour.Task{PayLoad: bodyBuff} 76 resBody, err := conf.Working(task) 77 78 if err != nil { 79 resBody = conf.ErrHandle(err) 80 } 81 return writeCore(resBody, conn, conf.WriteTimeout) 82 } 83 84 func releaseConn(conn net.Conn) { 85 if err := conn.Close(); err != nil { 86 nfour.NFourLogger.InfoLn(err) 87 } 88 } 89 90 func writeCore(res []byte, conn net.Conn, timeout time.Duration) bool { 91 conn.SetWriteDeadline(time.Now().Add(timeout)) 92 93 plen := len(res) 94 payload := make([]byte, plen+nfour.PayLoadLenBufLength) 95 copy(payload, bytutil.Int32ToBytes(int32(plen))) 96 copy(payload[nfour.PayLoadLenBufLength:], res) 97 98 n, err := conn.Write(payload) 99 if err != nil { 100 conn.Close() 101 nfour.NFourLogger.InfoLn(err) 102 return false 103 } 104 nfour.NFourLogger.Debug("write data:%d, expect:%d\n", n, plen+nfour.PayLoadLenBufLength) 105 return true 106 }