goSplice

package module
v1.0.5 Latest Latest
Warning

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

Go to latest
Published: Aug 2, 2026 License: MIT Imports: 6 Imported by: 0

README

go-splice gopher

go-splice

Go Reference

Pure Kernel-Space TCP bridge for Go.

Bridge copies bytes in both directions between two TCP connections until both sides close. On Linux the copy runs through the Go runtime's splice(2) fast path, so payload bytes move socket-to-socket in kernel space — no per-connection buffer, no GC churn. On every other platform it falls back to the standard buffered copy automatically.

No magic here. The zero-copy path belongs to the Go standard library, not to this package. io.Copy between two *net.TCPConn already uses splice(2). Bridge is ~25 lines of glue: two io.Copy calls, a clean half-close, and byte accounting — so you don't rewrite that in every relay.

Install

go get github.com/allenbiji/go-splice

Usage

A complete TCP proxy:

package main

import (
	"log"
	"net"

	gosplice "github.com/allenbiji/go-splice"
)

func main() {
	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatal(err)
	}
	defer ln.Close()
	log.Println("proxy listening on :8080")

	for {
		client, err := ln.Accept()
		if err != nil {
			continue
		}
		go handle(client.(*net.TCPConn))
	}
}

func handle(client *net.TCPConn) {
	defer client.Close()

	up, err := net.Dial("tcp", "127.0.0.1:9000")
	if err != nil {
		return
	}
	server := up.(*net.TCPConn)
	defer server.Close()

	n, err := gosplice.Bridge(client, server)
	if err != nil {
		log.Printf("bridge closed with error: %v", err)
		return
	}
	log.Printf("session closed, %d bytes relayed", n)
}

API

func Bridge(a, b *net.TCPConn) (int64, error)

Relays bytes in both directions between a and b until both directions reach EOF or error. Returns the total bytes relayed (a→b plus b→a) and the first non-nil error encountered.

As each direction finishes, Bridge half-closes the destination's write side (CloseWrite) so the peer sees a clean EOF instead of a reset. It returns only once both directions are done. Closing the connections themselves is left to the caller.

How it works

io.Copy(dst, src) checks whether the destination implements io.ReaderFrom (or the source implements io.WriterTo). *net.TCPConn does, and on Linux those methods take the splice(2) path: the runtime pulls a pipe from a pool, moves data socket→pipe→socket with SPLICE_F_NONBLOCK, and parks on the netpoller when a socket is empty. Bridge just runs that copy in both directions and half-closes each side when its direction ends.

You can confirm the fast path with strace -f -e trace=splice,pipe2 on any proxy built from io.Copy over TCP connections — you'll see splice() calls carrying the payload and no read/write of it into user space.

When to use

Use it for pure byte relays — load balancers, forward proxies, tunnels, P2P sidecars — where you don't touch the payload.

Don't use it (and don't expect the splice path) if you need to inspect, log, or modify the traffic, or if you're terminating TLS. A *tls.Conn isn't a *net.TCPConn, so io.Copy won't splice it.

Requirements

  • Go 1.11+ for the splice(2) fast path.
  • Linux for zero-copy. Other platforms fall back to a buffered copy automatically — no build tags needed.

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Bridge

func Bridge(clientConn, serverConn *net.TCPConn) (int64, error)

Bridge splices data in both directions between two TCP connections until both directions close, then returns the total bytes relayed across both.

Types

This section is empty.

Jump to

Keyboard shortcuts

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