Documentation
¶
Overview ¶
Package tcp provides a robust, production-ready TCP server implementation with support for TLS, connection management, and comprehensive monitoring capabilities.
Overview ¶
This package implements a high-performance TCP server that supports:
- TLS/SSL encryption with configurable cipher suites and protocols (TLS 1.2/1.3)
- Graceful shutdown with connection draining and timeout management
- Connection lifecycle monitoring with state callbacks
- Context-aware operations with cancellation propagation
- Configurable idle timeouts for inactive connections
- Thread-safe concurrent connection handling (goroutine-per-connection)
- Connection counting and tracking
- Customizable connection configuration via UpdateConn callback
Architecture ¶
## Component Diagram
The server follows a layered architecture with clear separation of concerns:
┌─────────────────────────────────────────────────────┐ │ TCP Server │ ├─────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌───────────────────┐ │ │ │ Listener │ │ Context Manager │ │ │ │ (Listen) │ │ (ctx tracking) │ │ │ └──────┬───────┘ └─────────┬─────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────────────────────────────────┐ │ │ │ Connection Acceptor │ │ │ │ (Accept loop + TLS handshake) │ │ │ └──────────────┬───────────────────────────┘ │ │ │ │ │ ▼ │ │ Per-Connection Goroutine │ │ ┌─────────────────────┐ │ │ │ Connection Context │ │ │ │ - sCtx (I/O wrap) │ │ │ │ - Idle timeout │ │ │ │ - State tracking │ │ │ └──────────┬──────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────┐ │ │ │ User Handler Func │ │ │ │ (custom logic) │ │ │ └─────────────────────┘ │ │ │ │ Optional Callbacks: │ │ - UpdateConn: Connection configuration │ │ - FuncError: Error reporting │ │ - FuncInfo: Connection state changes │ │ - FuncInfoSrv: Server lifecycle events │ │ │ └─────────────────────────────────────────────────────┘
## Data Flow
- Server.Listen() starts the accept loop
- For each new connection: a. net.Listener.Accept() receives the connection b. Optional TLS handshake (if configured) c. Connection counter incremented atomically d. UpdateConn callback invoked (if registered) e. Connection wrapped in sCtx (context + I/O) f. Handler goroutine spawned g. Idle timeout monitoring started (if configured)
- Handler processes the connection
- On close: a. Connection closed b. Context cancelled c. Counter decremented d. Goroutine terminates
## Lifecycle States
The server maintains two atomic state flags:
IsRunning: Server is accepting new connections
false → true: Listen() called successfully
true → false: Shutdown/Close initiated
IsGone: Server is draining existing connections
false → true: Shutdown() called
Used to signal accept loop to stop
## Thread Safety Model
Synchronization primitives used:
- atomic.Bool: run, gon (server state)
- atomic.Int64: nc (connection counter)
- libatm.Value: ssl, fe, fi, fs, ad (atomic storage)
- No mutexes: All state changes are lock-free
Concurrency guarantees:
- All exported methods are safe for concurrent use
- Connection handlers run in isolated goroutines
- No shared mutable state between connections
- Atomic counters prevent race conditions
Features ¶
## Security
- TLS 1.2/1.3 support with configurable cipher suites and curves
- Mutual TLS (mTLS) support for client authentication
- Secure defaults for TLS configuration (minimum TLS 1.2)
- Certificate validation and chain verification
- Integration with github.com/nabbar/golib/certificates for TLS management
## Reliability
- Graceful shutdown with configurable timeouts
- Connection draining during shutdown (wait for active connections)
- Automatic reclamation of resources (goroutines, memory, file descriptors)
- Idle connection timeout with automatic cleanup
- Context-aware operations with deadline and cancellation support
- Error recovery and propagation
## Monitoring & Observability
- Connection state change callbacks (new, read, write, close)
- Error reporting through callback functions
- Server lifecycle notifications
- Real-time connection counting (OpenConnections)
- Server state queries (IsRunning, IsGone)
## Performance
- Goroutine-per-connection model (suitable for 100s-1000s of connections)
- Lock-free atomic operations for state management
- Zero-copy I/O where possible
- Minimal memory overhead per connection (~10KB)
- Efficient connection tracking without locks
Usage Example ¶
Basic echo server:
import (
"context"
"io"
"github.com/nabbar/golib/socket"
tcp "github.com/nabbar/golib/socket/server/tcp"
)
func main() {
handler := func(r socket.Reader, w socket.Writer) {
defer r.Close()
defer w.Close()
io.Copy(w, r) // Echo back received data
}
srv, err := tcp.New(nil, handler, socket.DefaultServerConfig(":8080"))
if err != nil {
panic(err)
}
// Start the server
if err := srv.Listen(context.Background()); err != nil {
panic(err)
}
}
Concurrency Model ¶
## Goroutine-Per-Connection
The server uses a goroutine-per-connection model, where each accepted connection spawns a dedicated goroutine to handle it. This model is well-suited for:
- Low to medium concurrent connections (100s to low 1000s)
- Long-lived connections (WebSockets, persistent HTTP, SSH-like protocols)
- Applications requiring per-connection state and context
- Connections with varying processing times
- Connections requiring blocking I/O operations
## Scalability Characteristics
Typical performance profile:
┌─────────────────┬──────────────┬────────────────┬──────────────┐
│ Connections │ Goroutines │ Memory Usage │ Throughput │
├─────────────────┼──────────────┼────────────────┼──────────────┤
│ 10 │ ~12 │ ~100 KB │ Excellent │
│ 100 │ ~102 │ ~1 MB │ Excellent │
│ 1,000 │ ~1,002 │ ~10 MB │ Good │
│ 10,000 │ ~10,002 │ ~100 MB │ Fair* │
│ 100,000+ │ ~100,002+ │ ~1 GB+ │ Not advised │
└─────────────────┴──────────────┴────────────────┴──────────────┘
- At 10K+ connections, consider profiling and potentially switching to
an event-driven model or worker pool architecture.
## Memory Overhead
Per-connection memory allocation:
Base overhead: ~8 KB (goroutine stack) Connection context: ~1 KB (sCtx structure) Buffers (handler): Variable (depends on implementation) ───────────────────────────────── Total minimum: ~10 KB per connection
Example calculation for 1000 connections:
1000 connections × 10 KB = ~10 MB base + application buffers (e.g., 4KB read buffer × 1000 = 4 MB) = ~14 MB total for connections
## Alternative Patterns for High Concurrency
For scenarios with >10,000 concurrent connections, consider:
Worker Pool Pattern: Fixed number of worker goroutines processing connections from a queue. Trades connection isolation for better resource control.
Event-Driven Model: Single-threaded or few-threaded event loop (epoll/kqueue). Requires careful state machine design but scales to millions.
Connection Multiplexing: Use protocols that support multiplexing (HTTP/2, gRPC, QUIC). Reduces OS-level connection overhead.
Rate Limiting: Limit concurrent connections with a semaphore or connection pool. Prevents resource exhaustion under load spikes.
This package is optimized for the common case of hundreds to low thousands of connections with good developer ergonomics and code simplicity.
Performance Considerations ¶
## Throughput
The server's throughput is primarily limited by:
- Handler function complexity (CPU-bound operations)
- Network bandwidth and latency
- TLS overhead (if enabled): ~10-30% CPU cost for encryption
- System limits: File descriptors, port exhaustion, kernel tuning
Typical throughput (echo handler on localhost):
- Without TLS: ~500K requests/sec (small payloads)
- With TLS: ~350K requests/sec (small payloads)
- Network I/O: Limited by bandwidth, not server
## Latency
Expected latency profile:
┌──────────────────────┬─────────────────┐ │ Operation │ Typical Time │ ├──────────────────────┼─────────────────┤ │ Connection accept │ <1 ms │ │ TLS handshake │ 1-5 ms │ │ Handler spawn │ <100 µs │ │ Context creation │ <10 µs │ │ Read/Write syscall │ <100 µs │ │ Graceful shutdown │ 100 ms - 1 s │ └──────────────────────┴─────────────────┘
## Resource Limits
System-level limits to consider:
File Descriptors: - Each connection uses 1 file descriptor - Check: ulimit -n (default often 1024 on Linux) - Increase: ulimit -n 65536 or via /etc/security/limits.conf
Ephemeral Ports (client-side): - Default range: ~28,000 ports (varies by OS) - Tune: sysctl net.ipv4.ip_local_port_range
TCP Buffer Memory: - Per-connection send/receive buffers - Default: 87380 bytes (varies) - Tune: sysctl net.ipv4.tcp_rmem and tcp_wmem
Connection Tracking (firewall): - Conntrack table size limits active connections - Check: sysctl net.netfilter.nf_conntrack_max
Limitations ¶
## Known Limitations
- No built-in rate limiting or connection throttling
- No support for connection pooling or multiplexing
- Goroutine-per-connection model limits scalability >10K connections
- No built-in protocol framing (implement in handler)
- TLS session resumption not explicitly managed
- No built-in metrics export (Prometheus, etc.)
## Not Suitable For
- Ultra-high concurrency scenarios (>50K simultaneous connections)
- Low-latency HFT applications (<10µs response time)
- Systems requiring protocol multiplexing (use HTTP/2 or gRPC)
- Short-lived connections at very high rates (>100K conn/sec)
## Comparison with Alternatives
┌──────────────────┬────────────────┬──────────────────┬──────────────┐ │ Feature │ This Package │ net/http │ gRPC │ ├──────────────────┼────────────────┼──────────────────┼──────────────┤ │ Protocol │ Raw TCP │ HTTP/1.1, HTTP/2│ HTTP/2 │ │ Framing │ Manual │ Built-in │ Built-in │ │ TLS │ Optional │ Optional │ Optional │ │ Concurrency │ Per-conn │ Per-request │ Per-stream │ │ Complexity │ Low │ Medium │ High │ │ Best For │ Custom proto │ REST APIs │ RPC │ │ Max Connections │ ~1-10K │ ~10K+ │ ~10K+ │ └──────────────────┴────────────────┴──────────────────┴──────────────┘
Best Practices ¶
## Error Handling
Always register error callbacks:
srv.RegisterFuncError(func(errs ...error) { for _, err := range errs { log.Printf("Server error: %v", err) } })
Handle all errors in your handler:
handler := func(ctx libsck.Context) { defer ctx.Close() // Always close
buf := make([]byte, 4096) n, err := ctx.Read(buf) if err != nil { if err != io.EOF { log.Printf("Read error: %v", err) } return } // Process data... }
## Resource Management
Always use defer for cleanup:
defer srv.Close() // Server defer ctx.Close() // Connection (in handler)
Implement graceful shutdown:
sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
<-sigChan log.Println("Shutting down...")
shutdownCtx, cancel := context.WithTimeout( context.Background(), 30*time.Second) defer cancel()
if err := srv.Shutdown(shutdownCtx); err != nil { log.Printf("Shutdown error: %v", err) }
Monitor connection count:
go func() { ticker := time.NewTicker(10 * time.Second) defer ticker.Stop()
for range ticker.C { count := srv.OpenConnections() if count > warnThreshold { log.Printf("WARNING: High connection count: %d", count) } } }()
## Security
Always use TLS in production:
cfg.TLS.Enable = true cfg.TLS.Config = tlsConfig // From certificates package
Configure idle timeouts to prevent resource exhaustion:
cfg.ConIdleTimeout = 5 * time.Minute
Validate input in handlers (prevent injection, DoS, etc.)
Consider implementing rate limiting at the application level
## Testing
Test with concurrent connections:
for i := 0; i < numClients; i++ { go func() { conn, _ := net.Dial("tcp", serverAddr) defer conn.Close() // Test logic... }() }
Test graceful shutdown under load
Test with slow/misbehaving clients
Run with race detector: go test -race
Related Packages ¶
- github.com/nabbar/golib/socket: Base interfaces and types
- github.com/nabbar/golib/socket/config: Server configuration
- github.com/nabbar/golib/certificates: TLS certificate management
- github.com/nabbar/golib/network/protocol: Protocol constants
See the example_test.go file for runnable examples covering common use cases.
Package tcp provides a TCP server implementation with support for TLS, connection management, and various callback hooks for monitoring and error handling.
This package implements the github.com/nabbar/golib/socket.Server interface and provides a robust TCP server with features including:
- TLS/SSL support with certificate management
- Graceful shutdown with connection draining
- Connection lifecycle callbacks (new, read, write, close)
- Error and informational logging callbacks
- Atomic connection counting and state management
- Context-aware operations
See github.com/nabbar/golib/socket for the Server interface definition.
Example ¶
Example demonstrates a basic echo server. This is the simplest possible TCP server implementation.
package main
import (
"context"
"time"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
sckcfg "github.com/nabbar/golib/socket/config"
scksrt "github.com/nabbar/golib/socket/server/tcp"
)
func main() {
// Create handler function that echoes back received data
handler := func(c libsck.Context) {
defer func() { _ = c.Close() }()
buf := make([]byte, 1024)
for {
n, err := c.Read(buf)
if err != nil {
return
}
if n > 0 {
_, _ = c.Write(buf[:n])
}
}
}
// Create server configuration
cfg := sckcfg.Server{
Network: libptc.NetworkTCP,
Address: ":8080",
}
// Create server
srv, err := scksrt.New(nil, handler, cfg)
if err != nil {
panic(err)
}
// Start server
ctx := context.Background()
go func() {
_ = srv.Listen(ctx)
}()
// Wait for server to start
time.Sleep(100 * time.Millisecond)
// Shutdown after demonstration
_ = srv.Shutdown(ctx)
}
Example (Complete) ¶
Example_complete demonstrates a production-ready server with all features. This example shows error handling, monitoring, graceful shutdown, and logging.
package main
import (
"context"
"fmt"
"net"
"time"
libdur "github.com/nabbar/golib/duration"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
sckcfg "github.com/nabbar/golib/socket/config"
scksrt "github.com/nabbar/golib/socket/server/tcp"
)
func main() {
// Handler with proper error handling
handler := func(c libsck.Context) {
defer func() { _ = c.Close() }()
buf := make([]byte, 4096)
for c.IsConnected() {
n, err := c.Read(buf)
if err != nil {
return
}
if n > 0 {
if _, err := c.Write(buf[:n]); err != nil {
return
}
}
}
}
// Create configuration with idle timeout
cfg := sckcfg.Server{
Network: libptc.NetworkTCP,
Address: ":8081",
ConIdleTimeout: libdur.Minutes(5),
}
// Create server
srv, err := scksrt.New(nil, handler, cfg)
if err != nil {
fmt.Printf("Failed to create server: %v\n", err)
return
}
// Register monitoring callbacks
srv.RegisterFuncError(func(errs ...error) {
for _, e := range errs {
fmt.Printf("Server error: %v\n", e)
}
})
srv.RegisterFuncInfo(func(local, remote net.Addr, state libsck.ConnState) {
fmt.Printf("Connection %s from %s\n", state, remote)
})
// Start server
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
if err := srv.Listen(ctx); err != nil {
fmt.Printf("Server stopped: %v\n", err)
}
}()
// Wait for server to be ready
time.Sleep(50 * time.Millisecond)
fmt.Printf("Server running with %d connections\n", srv.OpenConnections())
// Graceful shutdown
shutdownCtx, shutdownCancel := context.WithTimeout(
context.Background(), 10*time.Second)
defer shutdownCancel()
if err := srv.Shutdown(shutdownCtx); err != nil {
fmt.Printf("Shutdown error: %v\n", err)
}
fmt.Println("Server stopped gracefully")
}
Output: Server running with 0 connections Server stopped gracefully
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidAddress is returned when the server address is empty or malformed. // The address must be in the format "host:port" or ":port" for all interfaces. // // Example of valid addresses: // - "localhost:8080" - Listen on localhost port 8080 // - ":8080" - Listen on all interfaces port 8080 // - "0.0.0.0:8080" - Explicitly listen on all IPv4 interfaces ErrInvalidAddress = fmt.Errorf("invalid listen address") // ErrInvalidHandler is returned when attempting to start a server without a valid handler function. // A handler must be provided via the New() constructor and must not be nil. // // Example of valid usage: // handler := func(r socket.Reader, w socket.Writer) { /* ... */ } // srv, err := tcp.New(nil, handler, config) ErrInvalidHandler = fmt.Errorf("invalid handler") // ErrShutdownTimeout is returned when the server shutdown exceeds the context timeout. // This typically happens when StopListen() takes longer than expected to complete. // The server will attempt to close all active connections before returning this error. // // To handle this error, you may want to implement a fallback strategy or log the event. ErrShutdownTimeout = fmt.Errorf("timeout on stopping socket") // ErrInvalidInstance is returned when operating on a nil server instance. // This typically occurs if the server was not properly initialized or has been set to nil. // Always check for this error when working with server instances that might be nil. ErrInvalidInstance = fmt.Errorf("invalid socket instance") )
Functions ¶
This section is empty.
Types ¶
type ServerTcp ¶
type ServerTcp interface {
libsck.Server
// RegisterServer sets the TCP address for the server to listen on.
// The address must be in the format "host:port" or ":port" to bind to all interfaces.
//
// Example addresses:
// - "127.0.0.1:8080" - Listen on localhost port 8080
// - ":8080" - Listen on all interfaces port 8080
// - "0.0.0.0:8080" - Explicitly listen on all IPv4 interfaces
//
// This method must be called before Listen(). Returns ErrInvalidAddress
// if the address is empty or malformed.
RegisterServer(address string) error
}
ServerTcp defines the interface for a TCP server implementation. It extends the base github.com/nabbar/golib/socket.Server interface with TCP-specific functionality.
Features ¶
## Connection Handling
- Concurrent connection handling with goroutine per connection
- Configurable idle timeout for connections
- Graceful connection draining during shutdown
- Connection state tracking and monitoring
## Security
- TLS/SSL encryption with configurable cipher suites
- Support for mutual TLS (mTLS) with client certificate verification
- Secure defaults for TLS configuration
## Monitoring & Observability
- Connection lifecycle callbacks (new, read, write, close)
- Error reporting through configurable callbacks
- Server status notifications
- Atomic counters for active connections
## Thread Safety
- All exported methods are safe for concurrent use
- Atomic operations for state management
- No shared state between connections
Lifecycle ¶
A typical server lifecycle follows these steps:
- Create: server := tcp.New(updateFunc, handler, config)
- Configure: server.RegisterServer(":8080")
- Start: server.Listen(ctx)
- (Run until shutdown signal)
- Shutdown: server.Shutdown(ctx)
Error Handling ¶
The server provides multiple ways to handle errors:
- Return values from methods (e.g., Listen(), Shutdown())
- Error callback function (RegisterFuncError)
- Context cancellation for timeouts
See github.com/nabbar/golib/socket.Server for inherited methods:
- Listen(context.Context) error - Start accepting connections
- Shutdown(context.Context) error - Graceful shutdown
- Close() error - Immediate shutdown
- IsRunning() bool - Check if server is accepting connections
- IsGone() bool - Check if all connections are closed
- OpenConnections() int64 - Get current connection count
- Done() <-chan struct{} - Channel closed when server stops listening
- SetTLS(bool, TLSConfig) error - Configure TLS
- RegisterFuncError(FuncError) - Register error callback
- RegisterFuncInfo(FuncInfo) - Register connection info callback
- RegisterFuncInfoServer(FuncInfoSrv) - Register server info callback
Example (ContextValues) ¶
ExampleServerTcp_contextValues demonstrates using context values
package main
import (
"context"
"fmt"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
sckcfg "github.com/nabbar/golib/socket/config"
scksrt "github.com/nabbar/golib/socket/server/tcp"
)
func main() {
type contextKey string
const userIDKey contextKey = "userID"
handler := func(c libsck.Context) {
defer func() { _ = c.Close() }()
// Access context value
if userID := c.Value(userIDKey); userID != nil {
fmt.Printf("Processing request for user: %v\n", userID)
}
}
cfg := sckcfg.Server{
Network: libptc.NetworkTCP,
Address: ":9011",
}
srv, _ := scksrt.New(nil, handler, cfg)
fmt.Println("Server with context values ready")
_ = srv.Shutdown(context.Background())
}
Output: Server with context values ready
Example (IdleTimeout) ¶
ExampleServerTcp_idleTimeout demonstrates idle connection timeout
package main
import (
"context"
"fmt"
"time"
libdur "github.com/nabbar/golib/duration"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
sckcfg "github.com/nabbar/golib/socket/config"
scksrt "github.com/nabbar/golib/socket/server/tcp"
)
func main() {
handler := func(c libsck.Context) {
defer func() { _ = c.Close() }()
// Handler that doesn't read/write (connection will idle)
time.Sleep(200 * time.Millisecond)
}
cfg := sckcfg.Server{
Network: libptc.NetworkTCP,
Address: ":9007",
ConIdleTimeout: libdur.ParseDuration(100 * time.Millisecond),
}
srv, _ := scksrt.New(nil, handler, cfg)
ctx := context.Background()
go func() {
_ = srv.Listen(ctx)
}()
time.Sleep(50 * time.Millisecond)
fmt.Println("Server with idle timeout running")
_ = srv.Shutdown(ctx)
}
Output: Server with idle timeout running
Example (Monitoring) ¶
ExampleServerTcp_monitoring demonstrates complete monitoring setup
package main
import (
"context"
"fmt"
"net"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
sckcfg "github.com/nabbar/golib/socket/config"
scksrt "github.com/nabbar/golib/socket/server/tcp"
)
func main() {
handler := func(c libsck.Context) {
defer func() { _ = c.Close() }()
}
cfg := sckcfg.Server{
Network: libptc.NetworkTCP,
Address: ":9009",
}
srv, _ := scksrt.New(nil, handler, cfg)
// Register all callbacks
srv.RegisterFuncError(func(errs ...error) {
fmt.Println("Error callback registered")
})
srv.RegisterFuncInfo(func(local, remote net.Addr, state libsck.ConnState) {
fmt.Println("Connection callback registered")
})
srv.RegisterFuncInfoServer(func(msg string) {
fmt.Println("Server info callback registered")
})
fmt.Println("All monitoring callbacks configured")
_ = srv.Shutdown(context.Background())
}
Output: All monitoring callbacks configured
func New ¶
func New(upd libsck.UpdateConn, hdl libsck.HandlerFunc, cfg sckcfg.Server) (ServerTcp, error)
New creates and initializes a new TCP server instance with the provided configuration.
Parameters ¶
upd: Optional UpdateConn callback that's invoked when a new connection is accepted, before the handler is called. Use this to configure connection-specific settings:
TCP keepalive
Read/write timeouts
Buffer sizes
Other TCP options
Example: upd := func(conn net.Conn) error { if tcpConn, ok := conn.(*net.TCPConn); ok { return tcpConn.SetKeepAlive(true) } return nil }
hdl: Required HandlerFunc that processes each client connection. This function runs in its own goroutine per connection. The handler receives:
r: A socket.Reader for reading from the client
w: A socket.Writer for writing to the client
Example echo server handler: hdl := func(r socket.Reader, w socket.Writer) { defer r.Close() defer w.Close() if _, err := io.Copy(w, r); err != nil { log.Printf("Error in handler: %v", err) } }
cfg: Server configuration including address, timeouts, and TLS settings. Use socket.DefaultServerConfig() for default values.
Return Value ¶
Returns a new ServerTcp instance that implements the Server interface. The server is not started until Listen() is called.
Example Usage ¶
Basic echo server:
func main() {
// Create a simple echo handler
handler := func(r socket.Reader, w socket.Writer) {
defer r.Close()
defer w.Close()
io.Copy(w, r) // Echo back received data
}
// Create server with default config
cfg := socket.DefaultServerConfig(":8080")
srv, err := tcp.New(nil, handler, cfg)
if err != nil {
log.Fatalf("Failed to create server: %v", err)
}
// Start the server
ctx := context.Background()
if err := srv.Listen(ctx); err != nil {
log.Fatalf("Server error: %v", err)
}
}
Error Handling ¶
The following errors may be returned:
- ErrInvalidHandler: if hdl is nil
- Any error returned by the configuration validation
Concurrency ¶
The returned server instance is safe for concurrent use by multiple goroutines. The handler function (hdl) may be called concurrently for different connections.
Memory Management ¶
The server manages the lifecycle of connections and associated resources. Ensure that all resources are properly closed by calling Shutdown() or Close() when the server is no longer needed.
See also:
- github.com/nabbar/golib/socket.HandlerFunc
- github.com/nabbar/golib/socket.UpdateConn
- github.com/nabbar/golib/socket/config.ServerConfig
Example ¶
ExampleNew demonstrates creating a TCP server
package main
import (
"fmt"
"io"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
sckcfg "github.com/nabbar/golib/socket/config"
scksrt "github.com/nabbar/golib/socket/server/tcp"
)
func main() {
// Define connection handler
handler := func(c libsck.Context) {
defer func() { _ = c.Close() }()
_, _ = io.Copy(c, c) // Echo
}
// Create configuration
cfg := sckcfg.Server{
Network: libptc.NetworkUDP,
Address: ":9000",
}
// Create server
srv, err := scksrt.New(nil, handler, cfg)
if err != nil {
fmt.Printf("Failed to create server: %v\n", err)
return
}
fmt.Printf("Server created successfully\n")
_ = srv
}
Output: Server created successfully
Example (SimpleProtocol) ¶
ExampleNew_simpleProtocol demonstrates a simple line-based protocol
package main
import (
"context"
"fmt"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
sckcfg "github.com/nabbar/golib/socket/config"
scksrt "github.com/nabbar/golib/socket/server/tcp"
)
func main() {
// Handler for a simple line-based protocol (newline-delimited)
handler := func(c libsck.Context) {
defer func() { _ = c.Close() }()
buf := make([]byte, 1024)
for {
n, err := c.Read(buf)
if err != nil {
return
}
// Echo each line back
if n > 0 {
_, _ = c.Write(buf[:n])
}
}
}
cfg := sckcfg.Server{
Network: libptc.NetworkTCP,
Address: ":9010",
}
srv, err := scksrt.New(nil, handler, cfg)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Println("Line-based protocol server created")
_ = srv.Shutdown(context.Background())
}
Output: Line-based protocol server created
Example (WithUpdateConn) ¶
ExampleNew_withUpdateConn demonstrates custom connection configuration
package main
import (
"context"
"fmt"
"net"
"time"
libptc "github.com/nabbar/golib/network/protocol"
libsck "github.com/nabbar/golib/socket"
sckcfg "github.com/nabbar/golib/socket/config"
scksrt "github.com/nabbar/golib/socket/server/tcp"
)
func main() {
// UpdateConn callback to configure TCP keepalive
upd := func(c net.Conn) {
if tcpConn, ok := c.(*net.TCPConn); ok {
_ = tcpConn.SetKeepAlive(true)
_ = tcpConn.SetKeepAlivePeriod(30 * time.Second)
}
}
handler := func(c libsck.Context) {
defer func() { _ = c.Close() }()
}
cfg := sckcfg.Server{
Network: libptc.NetworkTCP,
Address: ":9008",
}
srv, err := scksrt.New(upd, handler, cfg)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Println("Server with custom connection config created")
_ = srv.Shutdown(context.Background())
}
Output: Server with custom connection config created