Zero-allocation socket types and address machinery for Unix systems in Go.
Language: English | 简体中文 | Español | 日本語 | Français
sock provides zero-allocation sockaddr encoding, non-blocking socket operations, socket option control, and iofd.FD access for integration with async I/O runtimes.
- Zero-Allocation Addresses — Sockaddr types encode directly to kernel-facing structures;
Raw()returns anunsafe.Pointerwith no marshaling and no heap allocation. - Zero-Overhead Syscalls — All I/O paths use
zcallassembly entry points that call into the kernel without routing through the Go runtime scheduler. - Protocol Support — TCP, UDP, SCTP, Unix domain (stream/dgram/seqpacket), and raw IP sockets; IPv4 and IPv6 for each.
- Adaptive I/O — Three-Tier Progress Model (Strike-Spin-Adapt): operations return
iox.ErrWouldBlockimmediately by default; deadline-driven backoff engages only when explicitly set - io_uring Ready — Every socket exposes
FD() *iofd.FDfor direct integration withuring,takt, and other async I/O runtimes. - UDP Batch I/O —
SendMessages/RecvMessagesusesendmmsg(2)/recvmmsg(2)to process multiple datagrams per syscall; adaptive variants add deadline support. - Network Link Queries —
Links,LinkByName, andLinkByIndexprovide Linux-native link enumeration viazcall; used internally for IPv6 zone ID resolution. - Socket Option Control — Type-safe helpers for SO_KEEPALIVE, TCP_NODELAY, SO_LINGER, TCP_USER_TIMEOUT, TCP_NOTSENT_LOWAT, SO_BUSY_POLL, UDP_SEGMENT, UDP_GRO, and more.
The Sockaddr interface is the foundation of zero-allocation address handling:
type Sockaddr interface {
Raw() (unsafe.Pointer, uint32) // Direct kernel format
Family() uint16 // AF_INET, AF_INET6, AF_UNIX
}Address types (SockaddrInet4, SockaddrInet6, SockaddrUnix) embed raw kernel structures and return pointers directly, with no marshaling and no allocation.
NetSocket (base)
├── TCPSocket → TCPConn, TCPListener
├── UDPSocket → UDPConn
├── SCTPSocket → SCTPConn, SCTPListener (Linux)
├── UnixSocket → UnixConn, UnixListener
└── RawSocket → RawConn (CAP_NET_RAW)
All sockets expose FD() *iofd.FD for integration with io_uring and other async I/O mechanisms.
Application
↓
sock.TCPConn.Write(data)
↓
iofd.FD.Write()
↓
zcall.Write() ← Assembly entry point (no Go runtime)
↓
Linux Kernel
The zcall package provides raw syscall entry points for direct kernel interaction from sock.
The package follows the Three-Tier Progress Model (Strike-Spin-Adapt) for non-blocking I/O:
- Strike: System call — direct kernel hit via
zcall - Spin: Hardware yield — local atomic synchronization (
spin.Pause) - Adapt: Software backoff — external I/O readiness (progressive sleep)
sock implements Strike and Adapt. Spin is not used here because socket operations wait on the kernel or a network peer, not on local atomics.
Key behaviors:
- Non-blocking by default:
Read,Write,Accept, andDialoperations return immediately withiox.ErrWouldBlockif the kernel is not ready. - Deadline-driven adaptation: Only when a deadline is explicitly set (via
SetDeadline,SetReadDeadline, orSetWriteDeadline) does the operation enter a retry loop with progressive backoff. - Non-blocking Dial: Unlike
net.Dial, functions likeDialTCP4return immediately once the connection attempt starts. The TCP handshake may still be in progress (ErrInProgressis silently ignored). UseTCPDialerwith a timeout for blocking behavior:
// Non-blocking (returns immediately, handshake may be in progress)
conn, _ := sock.DialTCP4(nil, raddr)
// Blocking with timeout (waits for connection or timeout)
dialer := &sock.TCPDialer{Timeout: 5 * time.Second}
conn, _ := dialer.Dial4(nil, raddr)go get code.hybscloud.com/sock// Server
ln, _ := sock.ListenTCP4(&sock.TCPAddr{IP: net.ParseIP("0.0.0.0"), Port: 8080})
conn, _ := ln.Accept()
conn.Read(buf)
conn.Close()
// Client
conn, _ := sock.DialTCP4(nil, &sock.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8080})
conn.SetNoDelay(true)
conn.Write(data)// Server
conn, _ := sock.ListenUDP4(&sock.UDPAddr{Port: 5353})
n, addr, _ := conn.ReadFrom(buf)
conn.WriteTo(response, addr)
// Client
conn, _ := sock.DialUDP4(nil, &sock.UDPAddr{IP: net.ParseIP("8.8.8.8"), Port: 53})
conn.Write(query)
conn.Read(response)// Server
ln, _ := sock.ListenSCTP4(&sock.SCTPAddr{IP: net.ParseIP("0.0.0.0"), Port: 9000})
conn, _ := ln.Accept()
conn.Read(buf)
// Client with timeout
dialer := &sock.SCTPDialer{Timeout: 5 * time.Second}
conn, _ := dialer.Dial4(nil, &sock.SCTPAddr{IP: net.ParseIP("127.0.0.1"), Port: 9000})
conn.Write(data)// Stream
ln, _ := sock.ListenUnix("unix", &net.UnixAddr{Name: "/tmp/app.sock"})
conn, _ := ln.Accept()
// Datagram
conn, _ := sock.ListenUnixgram("unixgram", &net.UnixAddr{Name: "/tmp/app.dgram"})
// Socket pair
pair, _ := sock.UnixConnPair("unix")
pair[0].Write([]byte("ping"))
pair[1].Read(buf)// ICMP ping
sock, _ := sock.NewICMPSocket4()
sock.SendTo(icmpPacket, &net.IPAddr{IP: net.ParseIP("8.8.8.8")})
n, addr, _ := sock.RecvFrom(buf)// TCP tuning
conn.SetNoDelay(true) // Disable Nagle's algorithm
conn.SetKeepAlive(true) // Enable keepalive probes
conn.SetKeepAlivePeriod(30 * time.Second)
// Buffer sizes
sock.SetSendBuffer(conn.FD(), 256*1024)
sock.SetRecvBuffer(conn.FD(), 256*1024)
// SO_LINGER for immediate RST on close
sock.SetLinger(conn.FD(), true, 0)
// TCP_USER_TIMEOUT for dead connection detection (Linux)
sock.SetTCPUserTimeout(conn.FD(), 30000) // 30 seconds in milliseconds
// TCP_NOTSENT_LOWAT for reduced memory and latency (Linux)
sock.SetTCPNotsentLowat(conn.FD(), 16384)
// SO_BUSY_POLL for low-latency polling (Linux)
sock.SetBusyPoll(conn.FD(), 50) // 50 microseconds// Send multiple messages in a single syscall
msgs := []sock.UDPMessage{
{Addr: addr1, Buffers: [][]byte{data1}},
{Addr: addr2, Buffers: [][]byte{data2}},
}
n, _ := conn.SendMessages(msgs)
// Receive multiple messages
recvMsgs := []sock.UDPMessage{
{Buffers: [][]byte{make([]byte, 1500)}},
{Buffers: [][]byte{make([]byte, 1500)}},
}
n, _ = conn.RecvMessages(recvMsgs)
// UDP GSO (Generic Segmentation Offload)
sock.SetUDPSegment(conn.FD(), 1400) // Segment size
// UDP GRO (Generic Receive Offload)
sock.SetUDPGRO(conn.FD(), true)links, _ := sock.Links()
lo, _ := sock.LinkByName("lo")
byIndex, _ := sock.LinkByIndex(lo.Index)// Non-blocking read with iox.ErrWouldBlock
n, err := conn.Read(buf)
if err == iox.ErrWouldBlock {
// Kernel not ready, integrate with event loop or retry later
return
}
if err != nil {
// Real error (connection reset, closed, etc.)
return
}
// Blocking read with deadline
conn.SetReadDeadline(time.Now().Add(5 * time.Second))
n, err = conn.Read(buf)
if err == sock.ErrTimedOut {
// Deadline exceeded
}The package provides seamless conversion with Go's standard net types:
// Convert net.TCPAddr to Sockaddr (zero-allocation)
netAddr := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8080}
sockaddr := sock.TCPAddrToSockaddr(netAddr)
// Convert back to net.TCPAddr
tcpAddr := sock.SockaddrToTCPAddr(sockaddr)
// Type aliases for compatibility
var _ sock.Conn = conn // net.Conn compatible
var _ sock.Addr = addr // net.Addr compatible
// Note: Listeners return concrete types (*TCPConn, *UnixConn) for
// zero-allocation performance, not net.Conn as net.Listener requires.| Platform | Status |
|---|---|
| linux/amd64 | Full |
| linux/arm64 | Full |
| linux/riscv64 | Full |
| linux/loong64 | Full |
| darwin/arm64 | Partial |
| freebsd/amd64 | Cross-compile only |
MIT, see LICENSE.
©2025 Hayabusa Cloud Co., Ltd.