gws: 兼顾性能与用户友好的go websocket server

个人项目, 花了很多时间肝, 欢迎大家来品鉴
使用std net实现的websocket library, 无缝接入mux, gin, echo等各种路由/框架.

压测结果镇楼

  • machine: Ubuntu 20.04LTS VM (4C8T)
  • client: tcpkali
Server Connection Send Speed(msg/s) Payload size Download / Upload Bandwidth(Mbps)
gws 200 20000 2.34KiB 11614.442↓ 11556.101↑
gorilla 200 20000 2.34KiB 4244.398↓ 4188.711↑
gws 2000 500 2.34KiB 7906.156↓ 7914.797↑
gorilla 2000 500 2.34KiB 4263.545↓ 4260.077↑
gws 5000 50 2.34KiB 4941.188↓ 4943.667↑
gorilla 5000 50 2.34KiB -
gws 10000 10 2.34KiB 1980.124↓ 1977.561↑
gorilla 10000 10 2.34KiB 1972.556↓ 1979.981↑
gws 10000 20 2.34KiB 3952.788↓ 3959.341↑
gorilla 10000 20 2.34KiB -

- means exception

亮点

  • 无依赖
  • 不需要额外开启协程监听消息, 处理各种事件
  • 读写消息不返回错误, 它们在gws内部被适当的处理了
  • 通过了 autobahn-testsuite 所有的WebSocket Protocol测试用例

安装

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

核心接口

type Event interface {
    OnOpen(socket *Conn)
    OnError(socket *Conn, err error)
    OnClose(socket *Conn, code uint16, reason []byte)
    OnPing(socket *Conn, payload []byte)
    OnPong(socket *Conn, payload []byte)
    OnMessage(socket *Conn, message *Message)
}

快速开始

package main

import (
    "fmt"
    "github.com/lxzan/gws"
    "net/http"
)

func main() {
    var upgrader = gws.NewUpgrader(func(c *gws.Upgrader) {
        c.CompressEnabled = true
        c.CheckTextEncoding = true
        c.MaxContentLength = 32 * 1024 * 1024
        c.EventHandler = new(WebSocket)
    })

    http.HandleFunc("/connect", func(writer http.ResponseWriter, request *http.Request) {
        socket, err := upgrader.Accept(writer, request)
        if err != nil {
            return
        }
        socket.Listen()
    })

    _ = http.ListenAndServe(":3000", nil)
}

type WebSocket struct{}

func (c *WebSocket) OnClose(socket *gws.Conn, code uint16, reason []byte) {
    fmt.Printf("onclose: code=%d, payload=%s\n", code, string(reason))
}

func (c *WebSocket) OnError(socket *gws.Conn, err error) {
    fmt.Printf("onerror: err=%s\n", err.Error())
}

func (c *WebSocket) OnOpen(socket *gws.Conn) {
    println("connected")
}

func (c *WebSocket) OnPing(socket *gws.Conn, payload []byte) {
    fmt.Printf("onping: payload=%s\n", string(payload))
    socket.WritePong(payload)
}

func (c *WebSocket) OnPong(socket *gws.Conn, payload []byte) {}

func (c *WebSocket) OnMessage(socket *gws.Conn, message *gws.Message) {
    socket.WriteMessage(message.Typ(), message.Bytes())
    message.Close()
}

测试

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

image.png

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 10

有没有人尝尝鲜 :kissing_heart:

1年前 评论
xuexi_go 1年前

大佬,牛逼

1年前 评论
lxzan (楼主) 1年前
goStruct

有实际线上项目的案列嘛,不然不敢用。

1年前 评论
lxzan (楼主) 1年前
lxzan (楼主) 1年前

gws 遇到问题:

使用 chrome ,

WebSocket连接打开失败,请检查!
failed: Error during WebSocket handshake: Sent non-empty ‘Sec-WebSocket-Protocol’ header but no response was received

该怎么设置 Sec-WebSocket-Protocol ?

等待回答qq657642432

1年前 评论
lxzan (楼主) 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!