github.com/wangyougui/gf/v2@v2.6.5/net/gtcp/gtcp_server.go (about) 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/wangyougui/gf. 6 7 package gtcp 8 9 import ( 10 "crypto/tls" 11 "fmt" 12 "net" 13 "sync" 14 15 "github.com/wangyougui/gf/v2/container/gmap" 16 "github.com/wangyougui/gf/v2/errors/gcode" 17 "github.com/wangyougui/gf/v2/errors/gerror" 18 "github.com/wangyougui/gf/v2/text/gstr" 19 "github.com/wangyougui/gf/v2/util/gconv" 20 ) 21 22 const ( 23 // FreePortAddress marks the server listens using random free port. 24 FreePortAddress = ":0" 25 ) 26 27 const ( 28 defaultServer = "default" 29 ) 30 31 // Server is a TCP server. 32 type Server struct { 33 mu sync.Mutex // Used for Server.listen concurrent safety. -- The golang test with data race checks this. 34 listen net.Listener // TCP address listener. 35 address string // Server listening address. 36 handler func(*Conn) // Connection handler. 37 tlsConfig *tls.Config // TLS configuration. 38 } 39 40 // Map for name to server, for singleton purpose. 41 var serverMapping = gmap.NewStrAnyMap(true) 42 43 // GetServer returns the TCP server with specified `name`, 44 // or it returns a new normal TCP server named `name` if it does not exist. 45 // The parameter `name` is used to specify the TCP server 46 func GetServer(name ...interface{}) *Server { 47 serverName := defaultServer 48 if len(name) > 0 && name[0] != "" { 49 serverName = gconv.String(name[0]) 50 } 51 return serverMapping.GetOrSetFuncLock(serverName, func() interface{} { 52 return NewServer("", nil) 53 }).(*Server) 54 } 55 56 // NewServer creates and returns a new normal TCP server. 57 // The parameter `name` is optional, which is used to specify the instance name of the server. 58 func NewServer(address string, handler func(*Conn), name ...string) *Server { 59 s := &Server{ 60 address: address, 61 handler: handler, 62 } 63 if len(name) > 0 && name[0] != "" { 64 serverMapping.Set(name[0], s) 65 } 66 return s 67 } 68 69 // NewServerTLS creates and returns a new TCP server with TLS support. 70 // The parameter `name` is optional, which is used to specify the instance name of the server. 71 func NewServerTLS(address string, tlsConfig *tls.Config, handler func(*Conn), name ...string) *Server { 72 s := NewServer(address, handler, name...) 73 s.SetTLSConfig(tlsConfig) 74 return s 75 } 76 77 // NewServerKeyCrt creates and returns a new TCP server with TLS support. 78 // The parameter `name` is optional, which is used to specify the instance name of the server. 79 func NewServerKeyCrt(address, crtFile, keyFile string, handler func(*Conn), name ...string) (*Server, error) { 80 s := NewServer(address, handler, name...) 81 if err := s.SetTLSKeyCrt(crtFile, keyFile); err != nil { 82 return nil, err 83 } 84 return s, nil 85 } 86 87 // SetAddress sets the listening address for server. 88 func (s *Server) SetAddress(address string) { 89 s.address = address 90 } 91 92 // GetAddress get the listening address for server. 93 func (s *Server) GetAddress() string { 94 return s.address 95 } 96 97 // SetHandler sets the connection handler for server. 98 func (s *Server) SetHandler(handler func(*Conn)) { 99 s.handler = handler 100 } 101 102 // SetTLSKeyCrt sets the certificate and key file for TLS configuration of server. 103 func (s *Server) SetTLSKeyCrt(crtFile, keyFile string) error { 104 tlsConfig, err := LoadKeyCrt(crtFile, keyFile) 105 if err != nil { 106 return err 107 } 108 s.tlsConfig = tlsConfig 109 return nil 110 } 111 112 // SetTLSConfig sets the TLS configuration of server. 113 func (s *Server) SetTLSConfig(tlsConfig *tls.Config) { 114 s.tlsConfig = tlsConfig 115 } 116 117 // Close closes the listener and shutdowns the server. 118 func (s *Server) Close() error { 119 s.mu.Lock() 120 defer s.mu.Unlock() 121 if s.listen == nil { 122 return nil 123 } 124 return s.listen.Close() 125 } 126 127 // Run starts running the TCP Server. 128 func (s *Server) Run() (err error) { 129 if s.handler == nil { 130 err = gerror.NewCode(gcode.CodeMissingConfiguration, "start running failed: socket handler not defined") 131 return 132 } 133 if s.tlsConfig != nil { 134 // TLS Server 135 s.mu.Lock() 136 s.listen, err = tls.Listen("tcp", s.address, s.tlsConfig) 137 s.mu.Unlock() 138 if err != nil { 139 err = gerror.Wrapf(err, `tls.Listen failed for address "%s"`, s.address) 140 return 141 } 142 } else { 143 // Normal Server 144 var tcpAddr *net.TCPAddr 145 if tcpAddr, err = net.ResolveTCPAddr("tcp", s.address); err != nil { 146 err = gerror.Wrapf(err, `net.ResolveTCPAddr failed for address "%s"`, s.address) 147 return err 148 } 149 s.mu.Lock() 150 s.listen, err = net.ListenTCP("tcp", tcpAddr) 151 s.mu.Unlock() 152 if err != nil { 153 err = gerror.Wrapf(err, `net.ListenTCP failed for address "%s"`, s.address) 154 return err 155 } 156 } 157 // Listening loop. 158 for { 159 var conn net.Conn 160 if conn, err = s.listen.Accept(); err != nil { 161 err = gerror.Wrapf(err, `Listener.Accept failed`) 162 return err 163 } else if conn != nil { 164 go s.handler(NewConnByNetConn(conn)) 165 } 166 } 167 } 168 169 // GetListenedAddress retrieves and returns the address string which are listened by current server. 170 func (s *Server) GetListenedAddress() string { 171 if !gstr.Contains(s.address, FreePortAddress) { 172 return s.address 173 } 174 var ( 175 address = s.address 176 listenedPort = s.GetListenedPort() 177 ) 178 address = gstr.Replace(address, FreePortAddress, fmt.Sprintf(`:%d`, listenedPort)) 179 return address 180 } 181 182 // GetListenedPort retrieves and returns one port which is listened to by current server. 183 func (s *Server) GetListenedPort() int { 184 s.mu.Lock() 185 defer s.mu.Unlock() 186 if ln := s.listen; ln != nil { 187 return ln.Addr().(*net.TCPAddr).Port 188 } 189 return -1 190 }