Websocket: [вопрос] Этот веб-сокет гориллы ограничил широковещательное сообщение в секунду?

Созданный на 26 окт. 2020  ·  8Комментарии  ·  Источник: gorilla/websocket

Опишите проблему, с которой вы столкнулись
Я использую golang.org/x/net/websocket для трансляции около 100 сообщений в секунду, это не проблема, клиент может получать все сообщения, но когда я использую gorilla websocket, получаю только менее 10 сообщений, тогда websocket clientv будет поврежден .

Версии

Версия go: версия go go1.13.11 linux / amd64

версия пакета: c3dd95aea9779669bb3daafbd84ee0530c8ce1c1

"Покажи мне код!"
основной пакет

Импортировать (
"кодировка / json"
"github.com/gorilla/websocket"
"бревно"
"net / http"
"время"
)

const (
// Время, разрешенное для написания сообщения партнеру.
writeWait = 10 * время. секунда

// Time allowed to read the next pong message from the peer.
pongWait = 60 * time.Second

// Send pings to peer with this period. Must be less than pongWait.
pingPeriod = (pongWait * 9) / 10

// Maximum message size allowed from peer.
maxMessageSize = 512

)

var upgradeder = websocket.Upgrader {
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func (r * http.Request) bool {return true},
}

var newline = [] байт {'\ n'}

type Client struct {
концентратор * концентратор
conn * websocket.Conn
отправить сообщение чана
увидеть строку
}

type Hub struct {
карта клиентов [* Client] bool
широковещательный канал сообщение
зарегистрировать чан * Клиент
unregister chan * Client
}

func newHub () Hub {return & Hub {трансляция: make (chan msg),регистрация: make (chan * Client),unregister: make (chan * Client),клиенты: make (map [ Client] bool),
}

}

func (h * Hub) run () {
для {
Выбрать {
case client: = <-h.register:
h.clients [клиент] = истина
case client: = <-h.unregister:
если _, ок: = h.clients [клиент]; ОК {
удалить (h.clients, client)
закрыть (client.send)
}
case message: = <-h.broadcast:
для клиента: = диапазон h.clients {
if client.see == message.LogName {
client.send <- сообщение
}
//Выбрать {
// case client.send <- сообщение:
//По умолчанию:
// закрыть (client.send)
// удалить (h.clients, client)
//}
}
}
}
}

func (c * Client) readPump () {
defer func () {
c.hub.unregister <- c
_ = c.conn.Close ()
} ()
c.conn.SetReadLimit (maxMessageSize)
_ = c.conn.SetReadDeadline (time.Now (). Add (pongWait))
c.conn.SetPongHandler (func (string) error {_ = c.conn.SetReadDeadline (time.Now (). Add (pongWait)); return nil})
для {
_, сообщение, ошибка: = c.conn.ReadMessage ()
if err! = nil {
если websocket.IsUnexpectedCloseError (err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
ErrorLogger.Printf ("readPump завершился с ошибкой:% v", err)
}
перерыв
}

    type recv struct {
        LogName string `json:"logName"`
    }
    var rcv = &recv{}
    if err := json.Unmarshal(message, &rcv); err != nil {
        c.hub.unregister <- c
        ErrorLogger.Printf("%s",err)
        break
    }
    c.see = rcv.LogName
}

}

func (c * Client) writePump () {
тикер: = время.NewTicker (pingPeriod)
defer func () {
ticker.Stop ()
_ = c.conn.Close ()
} ()
для {
Выбрать {
case сообщение, ok: = <-c.send:
_ = c.conn.SetWriteDeadline (time.Now (). Add (writeWait))
if! ok {
// Хаб закрыл канал.
_ = c.conn.WriteMessage (websocket.CloseMessage, [] байт {})
возвращаться
}

        w, err := c.conn.NextWriter(websocket.TextMessage)
        if err != nil {
            return
        }
        msgByte, _ := json.Marshal(message)
        _, _ = w.Write(msgByte)

        // Add queued chat messages to the current websocket message.
        n := len(c.send)
        _, _ = w.Write(newline)
        for i := 0; i < n; i++ {
            for msg := range c.send {
                msgByte, _ := json.Marshal(msg)
                _, err := w.Write(msgByte)
                if err != nil {
                    newHub().unregister <- c
                    ErrorLogger.Printf("%s", err)
                    break
                }
            }
        }
        if err := w.Close(); err != nil {
            return
        }
    case <-ticker.C:
        _ = c.conn.SetWriteDeadline(time.Now().Add(writeWait))
        if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
            return
        }
    }
}

}

// serveWs обрабатывает запросы веб-сокетов от однорангового узла.
func serveWs (hub * Hub, w http.ResponseWriter, r * http.Request) {
conn, err: = upgradeder.Upgrade (w, r, nil)
if err! = nil {
log.Fatal (ошибка)
возвращаться
}
client: = & Client {hub: hub, conn: conn, send: make (chan msg, 1)}
client.hub.register <- клиент

// Allow collection of memory referenced by the caller by doing all work in
// new goroutines.
go client.writePump()
go client.readPump()

}

question

Самый полезный комментарий

Gorilla не имеет переменной или API, ограничивающего количество сообщений в секунду.

Код для упаковки нескольких документов JSON в одно сообщение WebSocket запустит затем отправку сообщений с очень высокой скоростью. Учитывая, что ваш клиент не предназначен для обработки нескольких документов JSON в одном сообщении WebSocket, вы можете ожидать, что ваше приложение потеряет сообщения при отправке сообщений с очень высокой скоростью.

Удалите код, процитированный парой комментариев, и проверьте снова.

Все 8 Комментарий

Ваш клиент написан для обработки нескольких документов JSON в одном сообщении WebSocket?

Покажите код с x / net / websocket, который работал.

Ваш клиент написан для обработки нескольких документов JSON в одном сообщении WebSocket?

Покажите код с x / net / websocket, который работал.

нет

основной пакет

Импортировать (
"кодировка / json"
"golang.org/x/net/websocket"
"io"
)

// веб-сокет 客户 端
type client struct {
строка идентификатора
сокет * websocket.Conn
отправить сообщение чана
увидеть строку
}

// 客户 端 管理
type clientManager struct {
карта клиентов [* клиент] bool
широковещательный канал сообщение
зарегистрировать чан * клиент
отменить регистрацию клиента chan *
}

var manager = clientManager {
трансляция: make (chan msg),
регистрация: make ( клиент чан


}

func (manager * clientManager) start () {
defer func () {
если ошибка: = восстановление (); err! = nil {
ErrorLogger.Printf ("паника при запуске () менеджера")
}
} ()

for {
    select {
    case conn := <-manager.register:
        manager.clients[conn] = true
    case conn := <-manager.unregister:
        if _, ok := manager.clients[conn]; ok {
            close(conn.send)
            _ = conn.socket.Close()
            delete(manager.clients, conn)
        }
    case msg := <-manager.broadcast:
        for conn := range manager.clients {
            if conn.see == msg.LogName {
                conn.send <- msg
            }
        }
    }
}

}

func (c * client) write () {

for msg := range c.send {
    msgByte, _ := json.Marshal(msg) // 忽略错误
    _, err := c.socket.Write(msgByte)
    if err != nil {
        manager.unregister <- c
        ErrorLogger.Printf("%s",err)
        break
    }
}

}

func (c * client) read () {
для {
строка ответа var
если ошибка: = websocket.Message.Receive (c.socket, & reply); err! = nil {
if err! = io.EOF {
ErrorLogger.Printf ("% s", ошибка)
manager.unregister <- c
}
перерыв
}
type recv struct {
Строка LogName json:"logName"
}
var rcv = & recv {}
если ошибка: = json.Unmarshal ([] байт (ответ), & rcv); err! = nil {
manager.unregister <- c
ErrorLogger.Printf ("% s", ошибка)
перерыв
}
c.see = rcv.LogName
}
}
``

В пакете gorilla нет ограничения на широковещательное сообщение в секунду.

Если ваш клиент не предназначен для обработки нескольких документов JSON в сообщении WebSocket, удалите код, который записывает несколько документов в сообщение.

Ваш код x / net / websocket записывает один документ JSON для каждого сообщения WebSocket. Если вы сделаете то же самое с кодом гориллы, приложение, вероятно, будет работать должным образом.

удалите код, который записывает несколько документов в сообщение.

ты имел ввиду это?

            // Add queued chat messages to the current websocket message.
            n := len(c.send)
            _, _ = w.Write(newline)
            for i := 0; i < n; i++ {
                for msg := range c.send {
                    msgByte, _ := json.Marshal(msg)
                    _, err := w.Write(msgByte)
                    if err != nil {
                        newHub().unregister <- c
                        ErrorLogger.Printf("%s", err)
                        break
                    }
                }
            }

Да, это ваш код, который добавляет несколько документов в сообщение веб-сокета.

Хорошо, у гориллы есть какая-нибудь переменная или API, которые могут заставить клиента получать больше сообщений за секунду?

Gorilla не имеет переменной или API, ограничивающего количество сообщений в секунду.

Код для упаковки нескольких документов JSON в одно сообщение WebSocket запустит затем отправку сообщений с очень высокой скоростью. Учитывая, что ваш клиент не предназначен для обработки нескольких документов JSON в одном сообщении WebSocket, вы можете ожидать, что ваше приложение потеряет сообщения при отправке сообщений с очень высокой скоростью.

Удалите код, процитированный парой комментариев, и проверьте снова.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги