One connection. Bidirectional RPC, acked messaging, and stream multiplexing — behind a single net.Conn.
Go
78
358 commits
updated Jul 10, 2026
One connection. Bidirectional RPC, acked messaging, and stream multiplexing — behind a single net.Conn.
You're building an IM server, a message queue, an API gateway, a reverse tunnel for NAT traversal, or a service-mesh sidecar. To get it right you need bidirectional RPC, reliable messaging with acks, many logical streams over one TCP connection, automatic reconnect, and all of it has to play nicely with Go's net.Conn / net.Listener.
The usual answer is: gRPC for RPC, yamux/smux for multiplexing, NATS or a custom protocol for messaging, and a tangle of glue to keep their lifecycles in sync. Geminio offers the whole bundle behind one interface.

| gRPC | yamux / smux | NATS | Geminio | |
|---|---|---|---|---|
| Request / response RPC | ✅ | — | — | ✅ |
| Server-initiated RPC to client | ⚠️ streaming only | — | — | ✅ |
| Messaging with publish/ack | — | — | ✅ | ✅ |
| Stream multiplexing | ✅ (HTTP/2) | ✅ | — | ✅ |
Drop-in net.Conn / net.Listener | — | ✅ | — | ✅ |
| Client-side auto-reconnect | — | — | ✅ | ✅ |
| Single binary, no broker | ✅ | ✅ | — | ✅ |
"Server-initiated RPC" means the server can
Call("method", ...)a handler the client registered — not just push messages on an open stream. It's the piece most "RPC libraries" don't ship.
Publish / Receive with delivery confirmation; sync and async.net.Conn / net.Listener compatible — streams drop into any code that speaks Go's net interfaces.ClientID and StreamID make routing, authz, and tracing straightforward.go get github.com/singchia/geminio
Every Geminio stream is a net.Conn, and every End is a net.Listener. So a server-initiated file transfer is just io.Copy — no framing, no codec, no broker.
Server — accept clients, open a stream back, copy the file in.
ln, _ := server.Listen("tcp", "127.0.0.1:8080")
for {
end, _ := ln.AcceptEnd()
go func() {
stream, _ := end.OpenStream()
defer stream.Close()
f, _ := os.Open("payload.bin")
defer f.Close()
io.Copy(stream, f)
}()
}
Client — treat the End as a net.Listener, save each incoming stream.
end, _ := client.NewEnd("tcp", "127.0.0.1:8080")
defer end.Close()
for {
conn, _ := end.Accept()
f, _ := os.Create("received.bin")
io.Copy(f, conn)
f.Close()
conn.Close()
}
The server initiates. The client listens on its own dial-out connection. io.Copy does the rest because the stream speaks net.Conn. Full runnable examples — RPC, bidirectional RPC, acked messaging, more multiplexing — in docs/USAGE.md.
| Scenario | Why Geminio fits | Example |
|---|---|---|
| NAT traversal / reverse tunnel | one outbound connection carries bidirectional control + many data streams | examples/traversal |
| Chatroom / IM | acked messaging, per-client IDs, auto-reconnect | examples/chatroom |
| Message queue | topics, ack, async publish | examples/mq |
| TCP relay / proxy | net.Conn-compatible streams over a control plane | examples/relay |
| API gateway / sidecar | bidirectional RPC + multiplexing + client identity | build directly on End |

Three layers — Connection (physical TCP, heartbeat, FSM), Multiplexer / Dialogue (logical streams, routing, write scheduling), and Application (RPC and messaging semantics) — let Geminio ship one unified End while keeping each concern isolated and testable. Deep dive in docs/MULTIPLEXING.md.
Apple M4 (2024 laptop-class CPU):
BenchmarkMessage-10 235592 14600 ns/op 8977 MB/s 68495 ops/sec
BenchmarkEnd-10 137131 25537 ns/op 5132 MB/s 39159 ops/sec
BenchmarkStream-10 137937 25853 ns/op 5069 MB/s 38680 ops/sec
BenchmarkRPC-10 84450 42527 ns/op 3082 MB/s 23515 ops/sec
~39K streams/sec at 5 GB/s, ~23K RPC round-trips/sec at 3 GB/s, ~68K short-message ops/sec at 8.9 GB/s. Run make bench on your own box.
docs/USAGE.mdexamples/docs/MULTIPLEXING.mdROADMAP.mdPRs and issues are welcome. See CONTRIBUTING.md. In short: one feature per PR, tests alongside code, run make test before submitting.
Apache 2.0 — © Austin Zhai, 2023–2030.
Made with OSS Insight
Overall
Maintained
Code review
Go module
Latest release
Releases this year
One connection. Bidirectional RPC, acked messaging, and stream multiplexing — behind a single net.Conn.
Go
78
358 commits
updated Jul 10, 2026
One connection. Bidirectional RPC, acked messaging, and stream multiplexing — behind a single net.Conn.
You're building an IM server, a message queue, an API gateway, a reverse tunnel for NAT traversal, or a service-mesh sidecar. To get it right you need bidirectional RPC, reliable messaging with acks, many logical streams over one TCP connection, automatic reconnect, and all of it has to play nicely with Go's net.Conn / net.Listener.
The usual answer is: gRPC for RPC, yamux/smux for multiplexing, NATS or a custom protocol for messaging, and a tangle of glue to keep their lifecycles in sync. Geminio offers the whole bundle behind one interface.

| gRPC | yamux / smux | NATS | Geminio | |
|---|---|---|---|---|
| Request / response RPC | ✅ | — | — | ✅ |
| Server-initiated RPC to client | ⚠️ streaming only | — | — | ✅ |
| Messaging with publish/ack | — | — | ✅ | ✅ |
| Stream multiplexing | ✅ (HTTP/2) | ✅ | — | ✅ |
Drop-in net.Conn / net.Listener | — | ✅ | — | ✅ |
| Client-side auto-reconnect | — | — | ✅ | ✅ |
| Single binary, no broker | ✅ | ✅ | — | ✅ |
"Server-initiated RPC" means the server can
Call("method", ...)a handler the client registered — not just push messages on an open stream. It's the piece most "RPC libraries" don't ship.
Publish / Receive with delivery confirmation; sync and async.net.Conn / net.Listener compatible — streams drop into any code that speaks Go's net interfaces.ClientID and StreamID make routing, authz, and tracing straightforward.go get github.com/singchia/geminio
Every Geminio stream is a net.Conn, and every End is a net.Listener. So a server-initiated file transfer is just io.Copy — no framing, no codec, no broker.
Server — accept clients, open a stream back, copy the file in.
ln, _ := server.Listen("tcp", "127.0.0.1:8080")
for {
end, _ := ln.AcceptEnd()
go func() {
stream, _ := end.OpenStream()
defer stream.Close()
f, _ := os.Open("payload.bin")
defer f.Close()
io.Copy(stream, f)
}()
}
Client — treat the End as a net.Listener, save each incoming stream.
end, _ := client.NewEnd("tcp", "127.0.0.1:8080")
defer end.Close()
for {
conn, _ := end.Accept()
f, _ := os.Create("received.bin")
io.Copy(f, conn)
f.Close()
conn.Close()
}
The server initiates. The client listens on its own dial-out connection. io.Copy does the rest because the stream speaks net.Conn. Full runnable examples — RPC, bidirectional RPC, acked messaging, more multiplexing — in docs/USAGE.md.
| Scenario | Why Geminio fits | Example |
|---|---|---|
| NAT traversal / reverse tunnel | one outbound connection carries bidirectional control + many data streams | examples/traversal |
| Chatroom / IM | acked messaging, per-client IDs, auto-reconnect | examples/chatroom |
| Message queue | topics, ack, async publish | examples/mq |
| TCP relay / proxy | net.Conn-compatible streams over a control plane | examples/relay |
| API gateway / sidecar | bidirectional RPC + multiplexing + client identity | build directly on End |

Three layers — Connection (physical TCP, heartbeat, FSM), Multiplexer / Dialogue (logical streams, routing, write scheduling), and Application (RPC and messaging semantics) — let Geminio ship one unified End while keeping each concern isolated and testable. Deep dive in docs/MULTIPLEXING.md.
Apple M4 (2024 laptop-class CPU):
BenchmarkMessage-10 235592 14600 ns/op 8977 MB/s 68495 ops/sec
BenchmarkEnd-10 137131 25537 ns/op 5132 MB/s 39159 ops/sec
BenchmarkStream-10 137937 25853 ns/op 5069 MB/s 38680 ops/sec
BenchmarkRPC-10 84450 42527 ns/op 3082 MB/s 23515 ops/sec
~39K streams/sec at 5 GB/s, ~23K RPC round-trips/sec at 3 GB/s, ~68K short-message ops/sec at 8.9 GB/s. Run make bench on your own box.
docs/USAGE.mdexamples/docs/MULTIPLEXING.mdROADMAP.mdPRs and issues are welcome. See CONTRIBUTING.md. In short: one feature per PR, tests alongside code, run make test before submitting.
Apache 2.0 — © Austin Zhai, 2023–2030.
Made with OSS Insight
Overall
Maintained
Code review
Go module
Latest release
Releases this year