Documentation
¶
Overview ¶
Package client provides a unified, platform-aware factory for creating socket clients across different network protocols. It serves as a convenient entry point that automatically selects the appropriate protocol-specific implementation based on the network type specified in the configuration.
Overview ¶
This package acts as a factory that abstracts protocol-specific client implementations and provides a consistent API through the github.com/nabbar/golib/socket.Client interface. The factory automatically delegates to the appropriate sub-package based on the protocol:
- TCP, TCP4, TCP6: github.com/nabbar/golib/socket/client/tcp
- UDP, UDP4, UDP6: github.com/nabbar/golib/socket/client/udp
- Unix (Linux/Darwin): github.com/nabbar/golib/socket/client/unix
- UnixGram (Linux/Darwin): github.com/nabbar/golib/socket/client/unixgram
Architecture ¶
## Factory Pattern
The client package implements the Factory Method pattern, providing a single entry point (New) that instantiates the appropriate client implementation:
┌─────────────────────────────────────────────────────┐
│ client.New() │
│ (Factory Function) │
└───────────────────────────┬─────────────────────────┘
│
┌─────────────┬─────┴───────┬───────────┐
│ │ │ │
▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ TCP │ │ UDP │ │ Unix │ │ UnixGram │
│ Client │ │ Client │ │ Client │ │ Client │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│ │ │ │
└─────────────┴──────┬──────┴─────────────┘
│
┌─────────▼─────────┐
│ socket.Client │
│ (Interface) │
└───────────────────┘
## Platform-Specific Implementations
The package uses build constraints to provide platform-specific implementations:
- interface_linux.go (//go:build linux): Full protocol support including Unix sockets
- interface_darwin.go (//go:build darwin): Full protocol support including Unix sockets
- interface_other.go (//go:build !linux && !darwin): TCP and UDP only
This ensures that Unix domain sockets are only available on platforms that support them.
## Component Diagram
┌───────────────────────────────────────────────────────────┐ │ client Package │ ├───────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────────┐ │ │ │ New(cfg, def) │ │ │ │ │ │ │ │ 1. Validate cfg.Network │ │ │ │ 2. Switch on protocol type │ │ │ │ 3. Delegate to appropriate package │ │ │ │ 4. Return socket.Client implementation │ │ │ └─────────────────────────┬───────────────────────┘ │ │ │ │ │ ▼ │ │ ┌───────────────┬──────┴────┬──────────────┐ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ │ │ tcp.New() udp.New() unix.New() unixgram.New() │ │ │ └───────────────────────────────────────────────────────────┘
Design Philosophy ¶
- Simplicity First: Single entry point (New) for all protocol types
- Platform Awareness: Automatic protocol availability based on OS
- Type Safety: Configuration-based client creation with validation
- Consistent API: All clients implement socket.Client interface
- Zero Overhead: Factory only adds a single switch statement
Key Features ¶
- Unified API: Single New() function for all protocols
- Platform-aware: Automatic Unix socket support detection
- Type-safe configuration: Uses config.Client struct
- Protocol validation: Returns error for unsupported protocols
- TLS support: Transparent TLS configuration for TCP clients
- Zero dependencies: Only delegates to sub-packages
- Minimal overhead: Direct delegation without wrapping
- Panic recovery: Automatic recovery with detailed logging
Usage Examples ¶
## TCP Client
import (
"github.com/nabbar/golib/network/protocol"
"github.com/nabbar/golib/socket/client"
"github.com/nabbar/golib/socket/config"
)
func main() {
cfg := config.Client{
Network: protocol.NetworkTCP,
Address: "localhost:8080",
}
cli, err := client.New(cfg, nil)
if err != nil {
panic(err)
}
defer cli.Close()
// Use client...
}
## TCP Client with TLS
import (
"github.com/nabbar/golib/certificates"
"github.com/nabbar/golib/socket/config"
)
// Create TLS config
tlsCfg := certificates.TLSConfig{
// Configure TLS...
}
cfg := config.Client{
Network: protocol.NetworkTCP,
Address: "secure.example.com:443",
TLS: config.ClientTLS{
Enabled: true,
ServerName: "secure.example.com",
},
}
cli, err := client.New(cfg, tlsCfg)
if err != nil {
panic(err)
}
defer cli.Close()
## UDP Client
cfg := config.Client{
Network: protocol.NetworkUDP,
Address: "localhost:9000",
}
cli, err := client.New(cfg, nil)
if err != nil {
panic(err)
}
defer cli.Close()
## Unix Socket Client (Linux/Darwin only)
cfg := config.Client{
Network: protocol.NetworkUnix,
Address: "/tmp/app.sock",
}
cli, err := client.New(cfg, nil)
if err != nil {
panic(err)
}
defer cli.Close()
Protocol Selection ¶
The New() function selects the appropriate client implementation based on cfg.Network value:
┌─────────────────────┬──────────────────┬─────────────────────┐ │ Protocol Value │ Platform │ Delegates To │ ├─────────────────────┼──────────────────┼─────────────────────┤ │ NetworkTCP │ All │ tcp.New() │ │ NetworkTCP4 │ All │ tcp.New() │ │ NetworkTCP6 │ All │ tcp.New() │ │ NetworkUDP │ All │ udp.New() │ │ NetworkUDP4 │ All │ udp.New() │ │ NetworkUDP6 │ All │ udp.New() │ │ NetworkUnix │ Linux/Darwin │ unix.New() │ │ NetworkUnixGram │ Linux/Darwin │ unixgram.New() │ │ Other values │ All │ ErrInvalidProtocol │ └─────────────────────┴──────────────────┴─────────────────────┘
Configuration ¶
The New() function accepts a config.Client struct containing:
- Network: Protocol type (NetworkTCP, NetworkUDP, NetworkUnix, etc.)
- Address: Protocol-specific address string
- TCP/UDP: "host:port" format
- Unix: filesystem path
- TLS: TLS configuration (TCP only)
- Enabled: Enable TLS
- Config: TLS certificate configuration
- ServerName: Server name for TLS verification
See github.com/nabbar/golib/socket/config.Client for complete configuration options.
Error Handling ¶
The New() function returns an error if:
Configuration validation fails Example: Empty address or invalid network value
Protocol is not supported on the current platform Example: NetworkUnix on Windows returns ErrInvalidProtocol
Protocol value is invalid or unrecognized Example: Undefined protocol constant returns ErrInvalidProtocol
Sub-package constructor fails Example: tcp.New() fails due to invalid address format
TLS configuration fails (TCP only) Example: Invalid TLS certificate or configuration
All errors are propagated from the underlying protocol implementation or configuration validation. The factory uses panic recovery to catch and log unexpected errors.
Platform Support ¶
## Linux (//go:build linux)
- Supported: TCP, TCP4, TCP6, UDP, UDP4, UDP6, Unix, UnixGram
- Unix sockets: Full support with abstract socket namespace
- Special features: Abstract sockets (addresses starting with @)
## Darwin/macOS (//go:build darwin)
- Supported: TCP, TCP4, TCP6, UDP, UDP4, UDP6, Unix, UnixGram
- Unix sockets: Full support with filesystem sockets
- Special features: Standard Unix socket features
## Other Platforms (//go:build !linux && !darwin)
- Supported: TCP, TCP4, TCP6, UDP, UDP4, UDP6
- Unix sockets: Not supported (returns ErrInvalidProtocol)
- Note: Includes Windows, BSD, Solaris, etc.
Thread Safety ¶
The New() function is thread-safe and can be called concurrently from multiple goroutines. Each call creates a new, independent client instance with its own state and resources.
The returned socket.Client implementations are also thread-safe for concurrent method calls, though each connection should typically be used by a single goroutine for reading and another for writing.
Performance Considerations ¶
## Factory Overhead
The client factory adds minimal overhead:
- One configuration validation
- One switch statement on protocol type
- One function call to the appropriate constructor
- No additional memory allocations
- No runtime reflection
Typical overhead: <1 microsecond per New() call.
## Protocol Performance Characteristics
┌──────────────┬──────────────┬─────────────┬──────────────────┐ │ Protocol │ Throughput │ Latency │ Best Use Case │ ├──────────────┼──────────────┼─────────────┼──────────────────┤ │ TCP │ High │ Low │ Network IPC │ │ UDP │ Very High │ Very Low │ Datagrams │ │ Unix │ Highest │ Lowest │ Local IPC │ │ UnixGram │ Highest │ Lowest │ Local datagrams │ └──────────────┴──────────────┴─────────────┴──────────────────┘
Limitations ¶
- Factory Only: This package provides no direct functionality, only delegation
- Platform-Specific: Unix socket support depends on OS (Linux/Darwin only)
- No Protocol Mixing: Each client handles only one protocol type
- No Auto-Detection: Protocol must be explicitly specified in configuration
- No Fallback: If a protocol is unsupported, an error is returned (no fallback)
- TLS for TCP Only: TLS configuration only applies to TCP-based protocols
Best Practices ¶
## 1. Use Appropriate Protocol for Use Case
// Local IPC between processes on same host cfg.Network = protocol.NetworkUnix // Lowest latency // Network communication cfg.Network = protocol.NetworkTCP // Reliable, ordered // Real-time datagrams (metrics, logging) cfg.Network = protocol.NetworkUDP // Fastest, connectionless
## 2. Handle Platform-Specific Errors
cli, err := client.New(cfg, nil)
if err == config.ErrInvalidProtocol {
// Protocol not supported on this platform
// Fall back to TCP
cfg.Network = protocol.NetworkTCP
cli, err = client.New(cfg, nil)
}
## 3. Configure Protocol-Specific Options
// TCP-specific: Enable TLS
if cfg.Network.IsTCP() {
cfg.TLS.Enabled = true
cfg.TLS.ServerName = "example.com"
}
## 4. Resource Management
cli, err := client.New(cfg, nil)
if err != nil {
return err
}
defer cli.Close() // Always clean up
// Use client...
## 5. Error Handling
cli, err := client.New(cfg, nil)
if err != nil {
if err == config.ErrInvalidProtocol {
// Handle unsupported protocol
} else {
// Handle other errors
}
return err
}
Comparison with Direct Protocol Packages ¶
## Using Factory (client.New)
Advantages:
- Single import for all protocols
- Consistent API across protocols
- Configuration-based client selection
- Easier to switch protocols
- Centralized error handling
Disadvantages:
- Slight indirection overhead
- Less explicit about protocol used
## Using Direct Protocol Packages
Advantages:
- More explicit (tcp.New vs client.New)
- Direct access to protocol-specific features
- Slightly better IDE autocomplete
Disadvantages:
- Multiple imports needed
- More code changes when switching protocols
- Repetitive error handling
Recommendation: Use client.New for most cases. Use protocol-specific packages when you need direct access to protocol-specific features or when protocol selection is static and won't change.
Related Packages ¶
- github.com/nabbar/golib/socket: Base interfaces and types
- github.com/nabbar/golib/socket/config: Client configuration structures
- github.com/nabbar/golib/socket/client/tcp: TCP client implementation
- github.com/nabbar/golib/socket/client/udp: UDP client implementation
- github.com/nabbar/golib/socket/client/unix: Unix socket client (Linux/Darwin)
- github.com/nabbar/golib/socket/client/unixgram: Unix datagram client (Linux/Darwin)
- github.com/nabbar/golib/network/protocol: Protocol constants and utilities
- github.com/nabbar/golib/certificates: TLS configuration and utilities
See Also ¶
For detailed documentation on individual protocol implementations, refer to:
- TCP clients: github.com/nabbar/golib/socket/client/tcp/doc.go
- UDP clients: github.com/nabbar/golib/socket/client/udp/doc.go
- Unix clients: github.com/nabbar/golib/socket/client/unix/doc.go
- UnixGram clients: github.com/nabbar/golib/socket/client/unixgram/doc.go
For examples, see example_test.go in this package.
Package client provides a unified factory for creating socket clients across different network protocols on Linux platforms.
This package serves as a convenience wrapper that creates appropriate client implementations based on the specified network protocol:
- TCP, TCP4, TCP6: Connection-oriented network sockets (see github.com/nabbar/golib/socket/client/tcp)
- UDP, UDP4, UDP6: Connectionless datagram network sockets (see github.com/nabbar/golib/socket/client/udp)
- Unix: Connection-oriented UNIX domain sockets (see github.com/nabbar/golib/socket/client/unix)
- UnixGram: Connectionless UNIX datagram sockets (see github.com/nabbar/golib/socket/client/unixgram)
All created clients implement the github.com/nabbar/golib/socket.Client interface, providing a consistent API regardless of the underlying protocol.
Example:
cfg := config.Client{
Network: protocol.NetworkTCP,
Address: "localhost:8080",
}
cli, err := client.New(cfg, nil)
if err != nil {
log.Fatal(err)
}
defer cli.Close()
Example ¶
Example demonstrates creating a basic TCP client using the factory. This is the simplest way to create a socket client.
package main
import (
"fmt"
libptc "github.com/nabbar/golib/network/protocol"
sckclt "github.com/nabbar/golib/socket/client"
sckcfg "github.com/nabbar/golib/socket/config"
)
func main() {
// Create client configuration
cfg := sckcfg.Client{
Network: libptc.NetworkTCP,
Address: "localhost:8080",
}
// Create client using factory
cli, err := sckclt.New(cfg, nil)
if err != nil {
fmt.Printf("Failed to create client: %v\n", err)
return
}
defer cli.Close()
fmt.Println("TCP client created successfully")
}
Output: TCP client created successfully
Example (ErrorHandling) ¶
Example_errorHandling demonstrates proper error handling patterns.
package main
import (
"fmt"
libptc "github.com/nabbar/golib/network/protocol"
sckclt "github.com/nabbar/golib/socket/client"
sckcfg "github.com/nabbar/golib/socket/config"
)
func main() {
cfg := sckcfg.Client{
Network: libptc.NetworkTCP,
Address: "localhost:9200",
}
cli, err := sckclt.New(cfg, nil)
if err != nil {
if err == sckcfg.ErrInvalidProtocol {
fmt.Println("Protocol not supported")
} else {
fmt.Printf("Failed to create client: %v\n", err)
}
return
}
defer cli.Close()
fmt.Println("Client created with proper error handling")
}
Output: Client created with proper error handling
Example (MultipleClients) ¶
Example_multipleClients demonstrates creating multiple clients with different protocols.
package main
import (
"fmt"
libptc "github.com/nabbar/golib/network/protocol"
sckclt "github.com/nabbar/golib/socket/client"
sckcfg "github.com/nabbar/golib/socket/config"
)
func main() {
// Create TCP client
tcpCfg := sckcfg.Client{
Network: libptc.NetworkTCP,
Address: "localhost:9100",
}
tcpCli, err := sckclt.New(tcpCfg, nil)
if err != nil {
fmt.Printf("TCP Error: %v\n", err)
return
}
defer tcpCli.Close()
// Create UDP client
udpCfg := sckcfg.Client{
Network: libptc.NetworkUDP,
Address: "localhost:9101",
}
udpCli, err := sckclt.New(udpCfg, nil)
if err != nil {
fmt.Printf("UDP Error: %v\n", err)
return
}
defer udpCli.Close()
fmt.Println("Multiple clients created successfully")
}
Output: Multiple clients created successfully
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func New ¶
New creates a new socket client based on the specified network protocol.
This factory function instantiates the appropriate client implementation for the given protocol type. On Linux platforms, all protocol types are supported, including UNIX domain sockets and abstract socket namespace.
Parameters:
- cfg: Client configuration from github.com/nabbar/golib/socket/config package. Contains network type, address, and optional TLS configuration. Supported network values:
- NetworkTCP, NetworkTCP4, NetworkTCP6: TCP clients
- NetworkUDP, NetworkUDP4, NetworkUDP6: UDP clients
- NetworkUnix: UNIX domain stream socket clients
- NetworkUnixGram: UNIX domain datagram socket clients
- def: Default TLS configuration (optional, can be nil). Used as a base for TCP client TLS configuration if cfg.TLS.Enabled is true.
Address format depends on the protocol:
- TCP/UDP: "host:port" format (e.g., "localhost:8080", "192.168.1.1:9000")
- UNIX: filesystem path (e.g., "/tmp/app.sock") or abstract socket (e.g., "@abstract")
Returns:
- libsck.Client: A client instance implementing the socket.Client interface
- error: An error if:
- Configuration validation fails (invalid network or empty address)
- Protocol is not supported on this platform
- Underlying protocol implementation fails to create client
- TLS configuration is invalid (TCP only)
The function uses panic recovery to catch and log unexpected errors during client creation. All panics are recovered and logged via RecoveryCaller.
Example:
// Create TCP client
cfg := config.Client{
Network: protocol.NetworkTCP,
Address: "localhost:8080",
}
cli, err := New(cfg, nil)
if err != nil {
log.Fatal(err)
}
defer cli.Close()
// Create UNIX socket client
unixCfg := config.Client{
Network: protocol.NetworkUnix,
Address: "/tmp/app.sock",
}
unixCli, err := New(unixCfg, nil)
if err != nil {
log.Fatal(err)
}
defer unixCli.Close()
// Create abstract UNIX socket client (Linux only)
abstractCfg := config.Client{
Network: protocol.NetworkUnix,
Address: "@myapp",
}
abstractCli, err := New(abstractCfg, nil)
if err != nil {
log.Fatal(err)
}
defer abstractCli.Close()
Example ¶
ExampleNew demonstrates creating a TCP client using the factory.
package main
import (
"fmt"
libptc "github.com/nabbar/golib/network/protocol"
sckclt "github.com/nabbar/golib/socket/client"
sckcfg "github.com/nabbar/golib/socket/config"
)
func main() {
// Create configuration
cfg := sckcfg.Client{
Network: libptc.NetworkTCP,
Address: "localhost:9000",
}
// Create client using factory
cli, err := sckclt.New(cfg, nil)
if err != nil {
fmt.Printf("Failed to create client: %v\n", err)
return
}
defer cli.Close()
fmt.Printf("Client created successfully\n")
}
Output: Client created successfully
Example (InvalidProtocol) ¶
ExampleNew_invalidProtocol demonstrates error handling for invalid protocols.
package main
import (
"fmt"
sckclt "github.com/nabbar/golib/socket/client"
sckcfg "github.com/nabbar/golib/socket/config"
)
func main() {
// Use an invalid protocol value
cfg := sckcfg.Client{
Network: 255, // Invalid protocol
Address: "localhost:9007",
}
cli, err := sckclt.New(cfg, nil)
if err != nil {
fmt.Println("Error: invalid protocol")
}
_ = cli
}
Output: Error: invalid protocol
Example (Tcp) ¶
ExampleNew_tcp demonstrates creating a TCP client.
package main
import (
"fmt"
libptc "github.com/nabbar/golib/network/protocol"
sckclt "github.com/nabbar/golib/socket/client"
sckcfg "github.com/nabbar/golib/socket/config"
)
func main() {
cfg := sckcfg.Client{
Network: libptc.NetworkTCP,
Address: "localhost:9001",
}
cli, err := sckclt.New(cfg, nil)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer cli.Close()
fmt.Println("TCP client created")
}
Output: TCP client created
Example (Tcp4) ¶
ExampleNew_tcp4 demonstrates creating a TCP4 client (IPv4 only).
package main
import (
"fmt"
libptc "github.com/nabbar/golib/network/protocol"
sckclt "github.com/nabbar/golib/socket/client"
sckcfg "github.com/nabbar/golib/socket/config"
)
func main() {
cfg := sckcfg.Client{
Network: libptc.NetworkTCP4,
Address: "127.0.0.1:9002",
}
cli, err := sckclt.New(cfg, nil)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer cli.Close()
fmt.Println("TCP4 client created")
}
Output: TCP4 client created
Example (Tcp6) ¶
ExampleNew_tcp6 demonstrates creating a TCP6 client (IPv6 only).
package main
import (
"fmt"
libptc "github.com/nabbar/golib/network/protocol"
sckclt "github.com/nabbar/golib/socket/client"
sckcfg "github.com/nabbar/golib/socket/config"
)
func main() {
cfg := sckcfg.Client{
Network: libptc.NetworkTCP6,
Address: "[::1]:9003",
}
cli, err := sckclt.New(cfg, nil)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer cli.Close()
fmt.Println("TCP6 client created")
}
Output: TCP6 client created
Example (TcpWithTLS) ¶
ExampleNew_tcpWithTLS demonstrates creating a TCP client with TLS configuration.
package main
import (
"fmt"
libptc "github.com/nabbar/golib/network/protocol"
sckclt "github.com/nabbar/golib/socket/client"
sckcfg "github.com/nabbar/golib/socket/config"
)
func main() {
cfg := sckcfg.Client{
Network: libptc.NetworkTCP,
Address: "localhost:9443",
}
cfg.TLS.Enabled = true
cfg.TLS.ServerName = "localhost"
cli, err := sckclt.New(cfg, nil)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer cli.Close()
fmt.Println("TCP client with TLS created")
}
Output: TCP client with TLS created
Example (Udp) ¶
ExampleNew_udp demonstrates creating a UDP client.
package main
import (
"fmt"
libptc "github.com/nabbar/golib/network/protocol"
sckclt "github.com/nabbar/golib/socket/client"
sckcfg "github.com/nabbar/golib/socket/config"
)
func main() {
cfg := sckcfg.Client{
Network: libptc.NetworkUDP,
Address: "localhost:9004",
}
cli, err := sckclt.New(cfg, nil)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer cli.Close()
fmt.Println("UDP client created")
}
Output: UDP client created
Example (Udp4) ¶
ExampleNew_udp4 demonstrates creating a UDP4 client (IPv4 only).
package main
import (
"fmt"
libptc "github.com/nabbar/golib/network/protocol"
sckclt "github.com/nabbar/golib/socket/client"
sckcfg "github.com/nabbar/golib/socket/config"
)
func main() {
cfg := sckcfg.Client{
Network: libptc.NetworkUDP4,
Address: "127.0.0.1:9005",
}
cli, err := sckclt.New(cfg, nil)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer cli.Close()
fmt.Println("UDP4 client created")
}
Output: UDP4 client created
Example (Udp6) ¶
ExampleNew_udp6 demonstrates creating a UDP6 client (IPv6 only).
package main
import (
"fmt"
libptc "github.com/nabbar/golib/network/protocol"
sckclt "github.com/nabbar/golib/socket/client"
sckcfg "github.com/nabbar/golib/socket/config"
)
func main() {
cfg := sckcfg.Client{
Network: libptc.NetworkUDP6,
Address: "[::1]:9006",
}
cli, err := sckclt.New(cfg, nil)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer cli.Close()
fmt.Println("UDP6 client created")
}
Output: UDP6 client created
Types ¶
This section is empty.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package tcp provides a robust, production-ready TCP client implementation with support for TLS, connection management, and comprehensive monitoring capabilities.
|
Package tcp provides a robust, production-ready TCP client implementation with support for TLS, connection management, and comprehensive monitoring capabilities. |
|
Package udp provides a UDP client implementation with callback mechanisms for datagram communication.
|
Package udp provides a UDP client implementation with callback mechanisms for datagram communication. |
|
Package unix provides a high-performance UNIX domain socket client implementation for local inter-process communication.
|
Package unix provides a high-performance UNIX domain socket client implementation for local inter-process communication. |
|
Package unixgram provides a Unix domain datagram socket client implementation.
|
Package unixgram provides a Unix domain datagram socket client implementation. |