Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
/gwsPublic

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

License

NotificationsYou must be signed in to change notification settings

lxzan/gws

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

中文

GWS

logo

Simple, Fast, Reliable WebSocket Server & Client

awesomecodecovGo Testgo-reportcardHelloGithublicensego-version

Introduction

GWS (Go WebSocket) is a very simple, fast, reliable and feature-rich WebSocket implementation written in Go. It isdesigned to be used in highly-concurrent environments, and it is suitable forbuildingAPI,Proxy,Game,Live Video,Message, etc. It supports both server and client side with a simple APIwhich mean you can easily write a server or client by yourself.

GWS developed base on Event-Driven model. every connection has a goroutine to handle the event, and the event is ableto be processed in a non-blocking way.

Why GWS

  • Simplicity and Ease of Use

    • User-Friendly: Simple and clearWebSocket Event API design makes server-client interaction easy.
    • Code Efficiency: Minimizes the amount of code needed to implement complex WebSocket solutions.
  • High-Performance

    • High IOPS Low Latency: Designed for rapid data transmission and reception, ideal for time-sensitiveapplications.
    • Low Memory Usage: Highly optimized memory multiplexing system to minimize memory usage and reduce your cost ofownership.
  • Reliability and Stability

    • Robust Error Handling: Advanced mechanisms to manage and mitigate errors, ensuring continuous operation.
    • Well-Developed Test Cases: Passed allAutobahn test cases, fully compliant withRFC 7692. Unit testcoverage is almost 100%, covering all conditional branches.

Benchmark

IOPS (Echo Server)

GOMAXPROCS=4, Connection=1000, CompressEnabled=false

performance

GoBench

gotest-benchmem-run=^$-bench .github.com/lxzan/gwsgoos:linuxgoarch:amd64pkg:github.com/lxzan/gwscpu:AMDRyzen5PRO4650GwithRadeonGraphicsBenchmarkConn_WriteMessage/compress_disabled-125263632232.3ns/op24B/op1allocs/opBenchmarkConn_WriteMessage/compress_enabled-129966311265ns/op386B/op1allocs/opBenchmarkConn_ReadMessage/compress_disabled-127809654152.4ns/op8B/op0allocs/opBenchmarkConn_ReadMessage/compress_enabled-123262573133ns/op81B/op1allocs/opPASSokgithub.com/lxzan/gws17.231s

Index

Feature

  • Event API
  • Broadcast
  • Dial via Proxy
  • Context-Takeover
  • Concurrent & Asynchronous Non-Blocking Write
  • Segmented Writing of Large Files
  • Passed Autobahn Test CasesServer /Client

Attention

  • The errors returned by the gws.Conn export methods are ignorable, and are handled internally.
  • Transferring large files with gws tends to block the connection.
  • If HTTP Server is reused, it is recommended to enable goroutine, as blocking will prevent the context from being GC.

Install

go get -v github.com/lxzan/gws@latest

Event

typeEventinterface {OnOpen(socket*Conn)// connection is establishedOnClose(socket*Conn,errerror)// received a close frame or input/output error occursOnPing(socket*Conn,payload []byte)// received a ping frameOnPong(socket*Conn,payload []byte)// received a pong frameOnMessage(socket*Conn,message*Message)// received a text/binary frame}

Quick Start

package mainimport"github.com/lxzan/gws"funcmain() {gws.NewServer(&gws.BuiltinEventHandler{},nil).Run(":6666")}

Best Practice

package mainimport ("github.com/lxzan/gws""net/http""time")const (PingInterval=5*time.SecondPingWait=10*time.Second)funcmain() {upgrader:=gws.NewUpgrader(&Handler{},&gws.ServerOption{ParallelEnabled:true,// Parallel message processingRecovery:gws.Recovery,// Exception recoveryPermessageDeflate: gws.PermessageDeflate{Enabled:true},// Enable compression})http.HandleFunc("/connect",func(writer http.ResponseWriter,request*http.Request) {socket,err:=upgrader.Upgrade(writer,request)iferr!=nil {return}gofunc() {socket.ReadLoop()// Blocking prevents the context from being GC.}()})http.ListenAndServe(":6666",nil)}typeHandlerstruct{}func (c*Handler)OnOpen(socket*gws.Conn) {_=socket.SetDeadline(time.Now().Add(PingInterval+PingWait))}func (c*Handler)OnClose(socket*gws.Conn,errerror) {}func (c*Handler)OnPing(socket*gws.Conn,payload []byte) {_=socket.SetDeadline(time.Now().Add(PingInterval+PingWait))_=socket.WritePong(nil)}func (c*Handler)OnPong(socket*gws.Conn,payload []byte) {}func (c*Handler)OnMessage(socket*gws.Conn,message*gws.Message) {defermessage.Close()socket.WriteMessage(message.Opcode,message.Bytes())}

More Examples

KCP

  • server
package mainimport ("log""github.com/lxzan/gws"kcp"github.com/xtaci/kcp-go")funcmain() {listener,err:=kcp.Listen(":6666")iferr!=nil {log.Println(err.Error())return}app:=gws.NewServer(&gws.BuiltinEventHandler{},nil)app.RunListener(listener)}
  • client
package mainimport ("github.com/lxzan/gws"kcp"github.com/xtaci/kcp-go""log")funcmain() {conn,err:=kcp.Dial("127.0.0.1:6666")iferr!=nil {log.Println(err.Error())return}app,_,err:=gws.NewClientFromConn(&gws.BuiltinEventHandler{},nil,conn)iferr!=nil {log.Println(err.Error())return}app.ReadLoop()}

Proxy

Dial via proxy, using socks5 protocol.

package mainimport ("crypto/tls""github.com/lxzan/gws""golang.org/x/net/proxy""log")funcmain() {socket,_,err:=gws.NewClient(new(gws.BuiltinEventHandler),&gws.ClientOption{Addr:"wss://example.com/connect",TlsConfig:&tls.Config{InsecureSkipVerify:true},NewDialer:func() (gws.Dialer,error) {returnproxy.SOCKS5("tcp","127.0.0.1:1080",nil,nil)},PermessageDeflate: gws.PermessageDeflate{Enabled:true,ServerContextTakeover:true,ClientContextTakeover:true,},})iferr!=nil {log.Println(err.Error())return}socket.ReadLoop()}

Broadcast

Create a Broadcaster instance, call the Broadcast method in a loop to send messages to each client, and close thebroadcaster to reclaim memory. The message is compressed only once.

funcBroadcast(conns []*gws.Conn,opcode gws.Opcode,payload []byte) {varb=gws.NewBroadcaster(opcode,payload)deferb.Close()for_,item:=rangeconns {_=b.Broadcast(item)    }}

WriteWithTimeout

SetDeadline covers most of the scenarios, but if you want to control the timeout for each write, you need toencapsulate theWriteWithTimeout function, the creation and destruction of thetimer will incur some overhead.

funcWriteWithTimeout(socket*gws.Conn,p []byte,timeout time.Duration)error {varsig= atomic.Uint32{}vartimer=time.AfterFunc(timeout,func() {ifsig.CompareAndSwap(0,1) {socket.WriteClose(1000, []byte("write timeout"))}})varerr=socket.WriteMessage(gws.OpcodeText,p)ifsig.CompareAndSwap(0,1) {timer.Stop()}returnerr}

Pub / Sub

Use the event_emitter package to implement the publish-subscribe model. Wrapgws.Conn in a structure and implement theGetSubscriberID method to get the subscription ID, which must be unique. The subscription ID is used to identify thesubscriber, 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 oneor more topics via websocket, and when a message is posted to that topic, all subscribers will receive the message.

package mainimport ("github.com/lxzan/event_emitter""github.com/lxzan/gws")typeSubscriber gws.ConnfuncNewSubscriber(conn*gws.Conn)*Subscriber {return (*Subscriber)(conn) }func (c*Subscriber)GetSubscriberID()int64 {userId,_:=c.GetMetadata().Load("userId")returnuserId.(int64)}func (c*Subscriber)GetMetadata() event_emitter.Metadata {returnc.Conn().Session() }func (c*Subscriber)Conn()*gws.Conn {return (*gws.Conn)(c) }funcSubscribe(em*event_emitter.EventEmitter[int64,*Subscriber],s*Subscriber,topicstring) {em.Subscribe(s,topic,func(msgany) {_=msg.(*gws.Broadcaster).Broadcast(s.Conn())    })}funcPublish(em*event_emitter.EventEmitter[int64,*Subscriber],topicstring,msg []byte) {varbroadcaster=gws.NewBroadcaster(gws.OpcodeText,msg)deferbroadcaster.Close()em.Publish(topic,broadcaster)}

Autobahn Test

cd examples/autobahnmkdir reportsdocker run -it --rm \    -v${PWD}/config:/config \    -v${PWD}/reports:/reports \    crossbario/autobahn-testsuite \    wstest -m fuzzingclient -s /config/fuzzingclient.json

Communication

微信需要先添加好友再拉群, 请注明来自 GitHub

WeChat    QQ

Buy me a coffee

WeChat

Acknowledgments

The following project had particular influence on gws's design.

About

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

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp