client

package
v1.19.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 4, 2026 License: MIT Imports: 9 Imported by: 0

README

Socket Client Factory

Go Version License Coverage

Platform-aware factory for creating socket clients across different network protocols (TCP, UDP, UNIX) with unified interface, TLS support, and automatic protocol selection.


Table of Contents


Overview

The client package provides a unified factory for creating socket clients across different network protocols. It automatically selects the appropriate protocol-specific implementation based on configuration while providing a consistent API through the github.com/nabbar/golib/socket.Client interface.

Design Philosophy
  1. Simplicity First: Single entry point (New) for all protocol types
  2. Platform Awareness: Automatic protocol availability based on OS
  3. Type Safety: Configuration-based client creation with validation
  4. Consistent API: All clients implement socket.Client interface
  5. Zero Overhead: Factory only adds a single switch statement
Key Features
  • Unified Factory: Single New() function for all protocols
  • Platform-Aware: Automatic Unix socket support detection
  • Type-Safe: Uses config.Client struct for configuration
  • 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

Architecture

Component Diagram
┌─────────────────────────────────────────────────────────┐
│                  client.New(cfg, def)                   │
│                   (Factory Function)                    │
└───────────────────────────┬─────────────────────────────┘
                            │
        ┌─────────────┬─────┴───────┬───────────┐
        │             │             │           │
        ▼             ▼             ▼           ▼
 ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐
 │   TCP    │  │   UDP    │  │   Unix   │  │ UnixGram │
 │  Client  │  │  Client  │  │  Client  │  │  Client  │
 └──────────┘  └──────────┘  └──────────┘  └──────────┘
      │             │             │             │
      └─────────────┴──────┬──────┴─────────────┘
                           │
                 ┌─────────▼─────────┐
                 │  socket.Client    │
                 │    (Interface)    │
                 └───────────────────┘
Factory Pattern

The package implements the Factory Method pattern:

Protocol Selection Logic:

New(cfg, def) → cfg.Network.IsTCP()    → tcp.New()
             → cfg.Network.IsUDP()    → udp.New()
             → cfg.Network.IsUnix()   → unix.New() (Linux/Darwin)
             → cfg.Network.IsUnixGram() → unixgram.New() (Linux/Darwin)
             → Unknown                → ErrInvalidProtocol

Advantages:

  • Single import for all protocols
  • Consistent API across protocols
  • Easy protocol switching via configuration
  • Centralized error handling

Trade-offs:

  • Slight indirection overhead (negligible)
  • Less explicit about protocol used
Platform Support
Platform TCP UDP Unix UnixGram
Linux
Darwin/macOS
Windows
Other

Performance

Benchmarks

Factory overhead is negligible:

Operation Time Overhead
Factory Call <1µs Single switch + function call
TCP Creation ~50µs Dominated by protocol implementation
UDP Creation ~40µs Dominated by protocol implementation
Unix Creation ~35µs Dominated by protocol implementation

Conclusion: Factory adds <1% overhead compared to direct protocol package usage.

Memory Usage
Base overhead:        ~0 bytes (no state stored)
Per client:           Same as direct protocol usage
Factory function:     Stack-only allocation

No heap allocations - factory is allocation-free.

Scalability
  • Concurrent Factory Calls: Thread-safe, tested with 100 concurrent goroutines
  • Client Independence: Each client is fully independent
  • Zero Shared State: No contention between clients

Use Cases

1. Multi-Protocol Application

Problem: Application needs to support multiple protocols based on configuration.

// Configuration-driven protocol selection
cfg := loadConfig()  // Returns config.Client

cli, err := client.New(cfg, nil)
if err != nil {
    log.Fatal(err)
}
defer cli.Close()

// Same code works for TCP, UDP, Unix
ctx := context.Background()
cli.Connect(ctx)
cli.Write([]byte("data"))

Real-world: Used in microservices that communicate via TCP over network or Unix sockets locally.

2. Platform-Specific Optimization

Problem: Use Unix sockets on Linux/Darwin, fall back to TCP on Windows.

// Try Unix first (fastest)
cfg := config.Client{
    Network: protocol.NetworkUnix,
    Address: "/tmp/app.sock",
}

cli, err := client.New(cfg, nil)
if err == config.ErrInvalidProtocol {
    // Fall back to TCP on unsupported platforms
    cfg.Network = protocol.NetworkTCP
    cfg.Address = "localhost:8080"
    cli, err = client.New(cfg, nil)
}
3. TLS Configuration Management

Problem: Centralized TLS configuration for TCP clients.

// Shared TLS config
tlsCfg := loadTLSConfig()

// Create multiple TCP clients with same TLS
for _, addr := range servers {
    cfg := config.Client{
        Network: protocol.NetworkTCP,
        Address: addr,
        TLS: config.ClientTLS{
            Enabled:    true,
            ServerName: extractHost(addr),
        },
    }
    
    cli, _ := client.New(cfg, tlsCfg)
    clients = append(clients, cli)
}
4. Testing with Protocol Mocking

Problem: Test application with different protocols without changing code.

// Production: Unix socket
prodCfg := config.Client{
    Network: protocol.NetworkUnix,
    Address: "/var/run/app.sock",
}

// Test: TCP socket for easier testing
testCfg := config.Client{
    Network: protocol.NetworkTCP,
    Address: "localhost:" + strconv.Itoa(testPort),
}

// Same application code
cfg := selectConfig(isTest)
cli, _ := client.New(cfg, nil)

Quick Start

Installation
go get github.com/nabbar/golib/socket/client
TCP Client

Simple TCP connection:

package main

import (
    "context"
    "log"
    
    libptc "github.com/nabbar/golib/network/protocol"
    sckcfg "github.com/nabbar/golib/socket/config"
    sckclt "github.com/nabbar/golib/socket/client"
)

func main() {
    // Create configuration
    cfg := sckcfg.Client{
        Network: libptc.NetworkTCP,
        Address: "localhost:8080",
    }
    
    // Create client using factory
    cli, err := sckclt.New(cfg, nil)
    if err != nil {
        log.Fatal(err)
    }
    defer cli.Close()
    
    // Connect and communicate
    ctx := context.Background()
    if err := cli.Connect(ctx); err != nil {
        log.Fatal(err)
    }
    
    cli.Write([]byte("Hello, server!"))
}
TCP with TLS

Secure TCP connection:

import (
    libtls "github.com/nabbar/golib/certificates"
)

func main() {
    // Configure TLS
    tlsCfg := libtls.NewTLSConfig()
    // ... configure certificates ...
    
    cfg := sckcfg.Client{
        Network: libptc.NetworkTCP,
        Address: "secure.example.com:443",
        TLS: sckcfg.ClientTLS{
            Enabled:    true,
            ServerName: "secure.example.com",
        },
    }
    
    cli, err := sckclt.New(cfg, tlsCfg)
    if err != nil {
        log.Fatal(err)
    }
    defer cli.Close()
    
    // Encrypted communication
    ctx := context.Background()
    cli.Connect(ctx)
    cli.Write([]byte("Secure data"))
}
UDP Client

Connectionless datagram communication:

func main() {
    cfg := sckcfg.Client{
        Network: libptc.NetworkUDP,
        Address: "localhost:9000",
    }
    
    cli, err := sckclt.New(cfg, nil)
    if err != nil {
        log.Fatal(err)
    }
    defer cli.Close()
    
    ctx := context.Background()
    cli.Connect(ctx)
    
    // Send datagram
    cli.Write([]byte("metric:value|type"))
}
UNIX Socket Client

High-performance local IPC (Linux/Darwin only):

func main() {
    cfg := sckcfg.Client{
        Network: libptc.NetworkUnix,
        Address: "/tmp/app.sock",
    }
    
    cli, err := sckclt.New(cfg, nil)
    if err != nil {
        if err == sckcfg.ErrInvalidProtocol {
            log.Fatal("Unix sockets not supported on this platform")
        }
        log.Fatal(err)
    }
    defer cli.Close()
    
    ctx := context.Background()
    cli.Connect(ctx)
    cli.Write([]byte("command"))
}
Error Handling

Proper error handling patterns:

func main() {
    cfg := sckcfg.Client{
        Network: libptc.NetworkUnix,
        Address: "/tmp/app.sock",
    }
    
    cli, err := sckclt.New(cfg, nil)
    if err != nil {
        if err == sckcfg.ErrInvalidProtocol {
            // Protocol not supported on this platform
            // Fall back to TCP
            cfg.Network = libptc.NetworkTCP
            cfg.Address = "localhost:8080"
            cli, err = sckclt.New(cfg, nil)
            if err != nil {
                log.Fatal(err)
            }
        } else {
            log.Fatal(err)
        }
    }
    defer cli.Close()
    
    // Use client...
}

Best Practices

✅ DO

Use Factory for Protocol Abstraction:

// ✅ Good: Configuration-driven
cfg := loadConfig()
cli, err := client.New(cfg, nil)
if err != nil {
    return err
}
defer cli.Close()

Handle Platform-Specific Protocols:

// ✅ Good: Check for platform support
cli, err := client.New(cfg, nil)
if err == config.ErrInvalidProtocol {
    // Handle unsupported protocol
    cfg.Network = protocol.NetworkTCP
    cli, err = client.New(cfg, nil)
}

Resource Management:

// ✅ Good: Always cleanup
cli, err := client.New(cfg, nil)
if err != nil {
    return err
}
defer cli.Close()  // Ensure cleanup

Context Usage:

// ✅ Good: Use context for timeouts
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

err := cli.Connect(ctx)
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) {
        return fmt.Errorf("connection timeout")
    }
    return err
}
❌ DON'T

Don't ignore protocol errors:

// ❌ BAD: Ignoring errors
cli, _ := client.New(cfg, nil)
cli.Connect(ctx)  // May panic on nil client

// ✅ GOOD: Check errors
cli, err := client.New(cfg, nil)
if err != nil {
    return err
}

Don't assume protocol availability:

// ❌ BAD: Assume Unix sockets available
cfg := config.Client{
    Network: protocol.NetworkUnix,
    Address: "/tmp/app.sock",
}
cli, _ := client.New(cfg, nil)  // Returns error on Windows

// ✅ GOOD: Check platform support
cli, err := client.New(cfg, nil)
if err == config.ErrInvalidProtocol {
    // Fall back to TCP
}

Don't create clients without cleanup:

// ❌ BAD: No cleanup
client.New(cfg, nil)

// ✅ GOOD: Always defer Close
cli, err := client.New(cfg, nil)
if err != nil {
    return err
}
defer cli.Close()

API Reference

Factory Function
func New(cfg sckcfg.Client, def libtls.TLSConfig) (libsck.Client, error)

Parameters:

  • cfg: Client configuration (network type, address, TLS settings)
  • def: Default TLS configuration (optional, can be nil)

Returns:

  • libsck.Client: Client instance implementing socket.Client interface
  • error: Error if configuration is invalid or protocol unsupported

Behavior:

  1. Validates configuration (Validate())
  2. Switches on cfg.Network type
  3. Delegates to appropriate protocol package
  4. Returns configured client or error

Panic Recovery: All panics are caught and logged via RecoveryCaller.

Configuration
type Client struct {
    Network NetworkProtocol  // Required: TCP, UDP, Unix, UnixGram
    Address string           // Required: "host:port" or "/path/to/socket"
    TLS     ClientTLS        // Optional: TLS configuration (TCP only)
}

type ClientTLS struct {
    Enabled    bool      // Enable TLS
    Config     TLSConfig // TLS certificates and settings
    ServerName string    // Server name for verification
}

Validation Rules:

  • Network must be valid protocol constant
  • Address must be non-empty
  • Unix sockets only on Linux/Darwin
Error Codes
var (
    ErrInvalidProtocol = errors.New("invalid protocol")
)

Error Scenarios:

Error Cause Action
ErrInvalidProtocol Protocol not supported on platform Fall back to supported protocol
ErrInvalidInstance Configuration validation failed Check cfg.Network and cfg.Address
Protocol-specific errors From underlying implementation See protocol package documentation

Contributing

Contributions are welcome! Please follow these guidelines:

  1. Code Quality

    • Follow Go best practices and idioms
    • Maintain or improve code coverage (target: >80%)
    • Pass all tests including race detector
    • Use gofmt and golint
  2. AI Usage Policy

    • AI must NEVER be used to generate package code or core functionality
    • AI assistance is limited to:
      • Testing (writing and improving tests)
      • Debugging (troubleshooting and bug resolution)
      • Documentation (comments, README, TESTING.md)
    • All AI-assisted work must be reviewed and validated by humans
  3. Testing

    • Add tests for new features
    • Use Ginkgo v2 / Gomega for test framework
    • Ensure zero race conditions
    • Test platform-specific code on target platforms
  4. Documentation

    • Update GoDoc comments for public APIs
    • Add examples for new features
    • Update README.md and TESTING.md if needed
  5. Pull Request Process

    • Fork the repository
    • Create a feature branch
    • Write clear commit messages
    • Ensure all tests pass
    • Update documentation
    • Submit PR with description of changes

Improvements & Security

Current Status

The package is production-ready with no urgent improvements or security vulnerabilities identified.

Code Quality Metrics
  • 81.2% test coverage (target: >80%)
  • Zero race conditions detected with -race flag
  • Thread-safe implementation using atomic operations
  • Panic recovery in all critical paths
  • Memory-safe with proper resource cleanup
Future Enhancements (Non-urgent)

The following enhancements could be considered for future versions:

  1. Protocol Auto-Detection: Automatically detect best protocol for given address
  2. Connection Pooling: Factory-managed connection pools per protocol
  3. Metrics Integration: Optional Prometheus metrics for factory usage
  4. Configuration Validation: Enhanced validation with detailed error messages

These are optional improvements and not required for production use. The current implementation is stable and performant.


Resources

Package Documentation
  • GoDoc - Complete API reference with function signatures, method descriptions, and runnable examples.

  • doc.go - In-depth package documentation including design philosophy, architecture diagrams, protocol selection logic, and best practices for production use.

  • TESTING.md - Comprehensive test suite documentation covering test architecture, BDD methodology with Ginkgo v2, coverage analysis (81.2%), and guidelines for writing new tests.

External References
  • Go net Package - Standard library networking primitives used by all protocol implementations.

  • Effective Go - Official Go programming guide covering best practices for interface design and error handling.

  • Factory Method Pattern - Design pattern documentation explaining the factory pattern used by this package.


AI Transparency

In compliance with EU AI Act Article 50.4: AI assistance was used for testing, documentation, and bug resolution under human supervision. All core functionality is human-designed and validated.


License

MIT License - See LICENSE file for details.

Copyright (c) 2025 Nicolas JUHEL


Maintained by: Nicolas JUHEL
Package: github.com/nabbar/golib/socket/client
Version: See releases for versioning

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

  1. Simplicity First: Single entry point (New) for all protocol types
  2. Platform Awareness: Automatic protocol availability based on OS
  3. Type Safety: Configuration-based client creation with validation
  4. Consistent API: All clients implement socket.Client interface
  5. 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:

  1. Configuration validation fails Example: Empty address or invalid network value

  2. Protocol is not supported on the current platform Example: NetworkUnix on Windows returns ErrInvalidProtocol

  3. Protocol value is invalid or unrecognized Example: Undefined protocol constant returns ErrInvalidProtocol

  4. Sub-package constructor fails Example: tcp.New() fails due to invalid address format

  5. 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

  1. Factory Only: This package provides no direct functionality, only delegation
  2. Platform-Specific: Unix socket support depends on OS (Linux/Darwin only)
  3. No Protocol Mixing: Each client handles only one protocol type
  4. No Auto-Detection: Protocol must be explicitly specified in configuration
  5. No Fallback: If a protocol is unsupported, an error is returned (no fallback)
  6. 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.

  • 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

func New(cfg sckcfg.Client, def libtls.TLSConfig) (libsck.Client, error)

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL