Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
G

gws

> 编程语言
Open source

simple, fast, reliable websocket server & client, supports running over tcp/kcp/unix domain socket. keywords: ws, proxy, chat, go, golang...

1.8K stars0 likes0 views
WebsiteGitHub

About

simple, fast, reliable websocket server & client, supports running over tcp/kcp/unix domain socket. keywords: ws, proxy, chat, go, golang...

[中文](README_CN.md)

Simple · High Performance · Reliable WebSocket Server & Client Library

### Introduction GWS (Go WebSocket) is a **simple, high‑performance and feature‑complete** WebSocket library written in Go. It is designed for **high‑concurrency** scenarios and is ideal for building **API gateways, long‑lived connection hubs, reverse proxies, IM / chat, online games, real‑time streaming, and push / subscribe systems**. GWS exposes an extremely **minimal, event‑driven API**, so you can build a stable WebSocket server or client with very little code. GWS is built on an event‑driven model: every connection has its own goroutine to drive the event loop, and events can be processed in a non‑blocking way. ### Why GWS - Simplicity & Developer Experience - **Event‑driven & intuitive**: The `Event` interface (`OnOpen / OnMessage / OnClose / OnPing / OnPong`) mirrors how you think about WebSocket lifecycles. - **High coding efficiency**: Protocol details are hidden behind a small, clear API, so you can focus almost entirely on business logic. - High Performance - **High throughput & low latency**: Carefully tuned for WebSocket workloads such as echo servers and long‑lived push streams, making it a great fit for latency‑sensitive applications. - **Low memory footprint**: Aggressive buffer reuse and compression strategies significantly reduce memory and CPU cost under heavy concurrency. - Reliability & Standards Compliance - **Robust error handling**: Clear, well‑defined behaviors for connection errors, protocol violations, compression failures, etc. - **Battle‑tested**: Passes all `Autobahn` test cases and is compliant with `RFC 6455` / `RFC 7692`. Unit tests cover almost all conditional branches. ### Benchmark #### IOPS (Echo Server) GOMAXPROCS=4, Connection=1000, CompressEnabled=false #### GoBench ``` … ``` ### Index - [Introduction](#introduction) - [Why GWS](#why-gws) - [Benchmark](#benchmark) - [IOPS (Echo Server)](#iops-echo-server) - [GoBench](#gobench) - [Index](#index) - [Feature](#feature) - [Attention](#attention) - [Install](#install) - [Event](#event) - [Reading APIs](#reading-apis) - [Quick Start](#quick-start) - [Best Practice](#best-practice) - [More Examples](#more-examples) - [KCP](#kcp) - [Proxy](#proxy) - [Broadcast](#broadcast) - [WriteWithTimeout](#writewithtimeout) - [Pub / Sub](#pub--sub) - [Autobahn Test](#autobahn-test) - [Ecosystem](#ecosystem) - [Communication](#communication) - [Buy me a coffee](#buy-me-a-coffee) - [Acknowledgments](#acknowledgments) ### Feature - [x] **Event‑driven API** based on the `Event` interface, similar to common WebSocket SDKs. - [x] **Broadcast support** via `Broadcaster`, which reuses compressed frames for efficient fan‑out. - [x] **Dial via proxy** using a customizable `Dialer` (e.g. SOCKS5 / HTTP proxy). - [x] **Context‑takeover (permessage‑deflate)** with configurable sliding window sizes. - [x] **Segmented writing of large files** with `WriteFile` to reduce peak memory during large transfers. - [x] **Concurrent & asynchronous non‑blocking write** with built‑in task queues and `Writev` / `WritevAsync`. - [x] **Strong standards compatibility**, passing all Autobahn test cases [Server report](https://lxzan.github.io/gws/reports/servers/) / [Client report](https://lxzan.github.io/gws/reports/clients/) ### Attention - For most business use‑cases, errors returned by exported methods on `gws.Conn` can be treated as **informational**: the library has already taken appropriate action internally (e.g. closing the connection, emitting events). - When transferring **very large files**, a single connection may occupy bandwidth and I/O for a long time; you may want throttling, sharding or other flow‑control at the business layer. - If you reuse `net/http` (e.g. call `Upgrade` inside an HTTP handler), always call `ReadLoop` inside a **separate goroutine**, otherwise blocking will prevent the request context from being garbage‑collected in time. ### Install ```bash go get -v github.com/lxzan/gws@latest ``` ### Event ```go type Event interface { OnOpen(socket *Conn) // connection is established OnClose(socket *Conn, err error) // received a close frame or input/output error occurs OnPing(socket *Conn, payload []byte) // received a ping frame OnPong(socket *Conn, payload []byte) // received a pong frame OnMessage(socket *Conn, message *Message) // received a text/binary frame } ``` ### Reading APIs `Conn` provides three read models. `ReadLoop` is event-driven and fits most server-side use-cases; `ReadMessage` manually pulls a complete message; `NextReader` streams message payloads and helps avoid holding a whole message in memory. | API | OnOpen | OnMessage | OnPing / OnPong | OnClose | Use case | | --- | --- | --- | --- | --- | --- | | `ReadLoop` | ✅ | ✅ | ✅ | ✅ | Regular event-driven server / client | | `ReadMessage` | ❌ | ❌ | ✅ | ✅ | Manually read one complete message | | `NextReader` | ❌ | ❌ | ✅ | ✅ | Stream message payloads and reduce whole-message copies | Notes: - Do not mix multiple read APIs on the same connection, and do not read concurrently. Pick one model: `ReadLoop`, `ReadMessage`, or `NextReader`. - When using `ReadLoop` inside an upgraded `net/http` request, run it in a new goroutine so the request context can be garbage-collected. - `ReadMessage` returns a `Message`; call `Close` after use to recycle its buffer. - `NextReader` returns a streaming `io.Reader`. It does not trigger `OnMessage` and does not validate UTF-8 text payloads. If the previous message was not fully consumed, the next `NextReader` call discards the remaining bytes first. #### ReadMessage ```go for { message, err := socket.ReadMessage() if err != nil { return } func() { defer message.Close() _ = socket.WriteMessage(message.Opcode, message.Bytes()) }() } ``` #### NextReader ```go for { messageType, r, err := socket.NextReader() if err != nil { return } data, err := io.ReadAll(r) if err != nil { return } _ = socket.WriteMessage(messageType, data) } ``` ### Quick Start ```go package main import "github.com/lxzan/gws" func main() { gws.NewServer(&gws.BuiltinEventHandler{}, nil).Run(":6666") } ``` ### Best Practice ``` … ``` ### More Examples #### KCP - server ```go package main import ( "log" "github.com/lxzan/gws" kcp "github.com/xtaci/kcp-go" ) func main() { listener, err := kcp.Listen(":6666") if err != nil { log.Println(err.Error()) return } app := gws.NewServer(&gws.BuiltinEventHandler{}, nil) app.RunListener(listener) } ``` - client ```go package main import ( "github.com/lxzan/gws" kcp "github.com/xtaci/kcp-go" "log" ) func main() { conn, err := kcp.Dial("127.0.0.1:6666") if err != nil { log.Println(err.Error()) return } app, _, err := gws.NewClientFromConn(&gws.BuiltinEventHandler{}, nil, conn) if err != nil { log.Println(err.Error()) return } app.ReadLoop() } ``` #### Proxy Dial via proxy, using socks5 protocol. ``` … ``` #### Broadcast Create a Broadcaster instance, call the Broadcast method in a loop to send messages to each client, and close the broadcaster to reclaim memory. The message is compressed only once. ```go func Broadcast(conns []*gws.Conn, opcode gws.Opcode, payload []byte) { var b = gws.NewBroadcaster(opcode, payload) defer b.Close() for _, item := range conns { _ = b.Broadcast(item, nil) } } ``` #### WriteWithTimeout `SetDeadline` covers most of the scenarios, but if you want to control the timeout for each write, you need to encapsulate the `WriteWithTimeout` function, the creation and destruction of the `timer` will incur some overhead. ```go func WriteWithTimeout(socket *gws.Conn, p []byte, timeout time.Duration) error { var sig = atomic.Uint32{} var timer = time.AfterFunc(timeout, func() { if sig.CompareAndSwap(0, 1) { socket.WriteClose(1000, []byte("write timeout")) } }) var err = socket.WriteMessage(gws.OpcodeText, p) if sig.CompareAndSwap(0, 1) { timer.Stop() } return err } ``` #### Pub / Sub Use the event_emitter package to implement the publish-subscribe model. Wrap `gws.Conn` in a structure and implement the GetSubscriberID method to get the subscription ID, which must be unique. The subscription ID is used to identify the subscriber, who can only receive messages on the subject of his subscription. This example is useful for building chat rooms or push messages using gws. This means that a user can subscribe to one or more topics via websocket, and when a message is posted to that topic, all subscribers will receive the message. ``` … ``` ### Autobahn Test ```bash cd examples/autobahn mkdir reports docker run -it --rm \ -v ${PWD}/config:/config \ -v ${PWD}/reports:/reports \ crossbario/autobahn-testsuite \ wstest -m fuzzingclient -s /config/fuzzingclient.json ``` ### Ecosystem - [proxy-connect-dialer-go](https://github.com/elastic/proxy-connect-dialer-go) - Custom dialer that sends headers to the proxy server during CONNECT requests. ### Communication > 微信需要先添加好友再拉群, 请注明来自 GitHub ### Buy me a coffee ### Acknowledgments The following project had particular influence on gws's design. - [crossbario/autobahn-testsuite](https://github.com/crossbario/autobahn-testsuite) - [klauspost/compress](https://github.com/klauspost/compress) - [lesismal/nbio](https://github.com/lesismal/nbio)

GitHub Issues· 0 open

View all on GitHub

No open issues yet, or sync has not completed.

Highlights

  • •<font size=3>Simplicity & Developer Experience</font>
  • •Event‑driven & intuitive: The Event interface (OnOpen / OnMessage / OnClose / OnPing / OnPong) mirrors how you think about WebSocket lifecycles.
  • •High coding efficiency: Protocol details are hidden behind a small, clear API, so you can focus almost entirely on business logic.
  • •<font size=3>High Performance</font>
  • •High throughput & low latency: Carefully tuned for WebSocket workloads such as echo servers and long‑lived push streams, making it a great fit for latency‑sensitive applications.
  • •Low memory footprint: Aggressive buffer reuse and compression strategies significantly reduce memory and CPU cost under heavy concurrency.
  • •<font size=3>Reliability & Standards Compliance</font>
  • •Robust error handling: Clear, well‑defined behaviors for connection errors, protocol violations, compression failures, etc.
  • •Battle‑tested: Passes all Autobahn test cases and is compliant with RFC 6455 / RFC 7692. Unit tests cover almost all conditional branches.
  • •Introduction

> Tags

Gocontext-takeovergo-websocketgo-wskcp

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言