рдЙрд╕ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВ рдЬреЛ рдЖрдк рдХрд░ рд░рд╣реЗ рд╣реИрдВ
рдореИрдВ рдПрдХ рд╕реЗрдХрдВрдб рдореЗрдВ 100 рд╕рдВрджреЗрд╢ рдкреНрд░рд╕рд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП golang.org/x/net/websocket рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реИ, рдЧреНрд░рд╛рд╣рдХ рдХреЛ рд╕рднреА рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЬрдм рдореИрдВ рдЧреЛрд░рд┐рд▓реНрд▓рд╛ рд╡реЗрдмрд╕реНрдХреЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ, рддреЛ рдХреЗрд╡рд▓ 10 рд╕реЗ рдХрдо рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ, рдлрд┐рд░ webckcket clientv рднреНрд░рд╖реНрдЯ рд╣реЛ рдЬрд╛рдПрдЧрд╛ ред
тАж
рд╕рдВрд╕реНрдХрд░рдгреЛрдВ
рдЧреЛ рд╕рдВрд╕реНрдХрд░рдг: рдЧреЛ рд╕рдВрд╕реНрдХрд░рдг go1.13.11 linux / amd64
рдкреИрдХреЗрдЬ рд╕рдВрд╕реНрдХрд░рдг: c3dd95aea9779669bb3daafbd84ee0530c8ce1f1
тАж
"рдореБрдЭреЗ рдХреЛрдб рджрд┐рдЦрд╛рдУ!"
рдкреИрдХреЗрдЬ рдореБрдЦреНрдп
рдЖрдпрд╛рдд (
"рдПрдиреНрдХреЛрдбрд┐рдВрдЧ / рдЬрд╕рди"
"github.com/gorilla/websocket"
"рд▓реЙрдЧ"
"рдиреЗрдЯ / http"
"рд╕рдордп"
)
const (
// рд╕рдордп рдиреЗ рд╕рд╣рдХрд░реНрдореА рдХреЛ рдПрдХ рд╕рдВрджреЗрд╢ рд▓рд┐рдЦрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреАред
рд░рд╛рдЗрдЯрд╡рд╛рдЗрдЯ = 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 upgrader = websocket.Upgrader {
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func (r * http.Request) рдмреВрд▓ {рд╡рд╛рдкрд╕реА рд╕рдЪ},
}
var newline = [] рдмрд╛рдЗрдЯ {'\ n'}
рдЯрд╛рдЗрдк рдХреНрд▓рд╛рдЗрдВрдЯ рд╕рдВрд░рдЪрдирд╛ {
рд╣рдм * рд╣рдм
con * websocket.Conn
рдЪреИрди рд╕рдВрджреЗрд╢ рднреЗрдЬреЗрдВ
рд╕реНрдЯреНрд░рд┐рдВрдЧ рджреЗрдЦреЗрдВ
}
рдкреНрд░рдХрд╛рд░ рд╣рдм рд╕рдВрд░рдЪрдирд╛ {
рдХреНрд▓рд╛рдЗрдВрдЯ рдореИрдк [* рдХреНрд▓рд╛рдЗрдВрдЯ] рдмреВрд▓
рдЪреИрди рд╕рдВрджреЗрд╢ рдкреНрд░рд╕рд╛рд░рд┐рдд рдХрд░реЗрдВ
рд░рдЬрд┐рд╕реНрдЯрд░ рдЪрд╛рди * рдЧреНрд░рд╛рд╣рдХ
рдЕрдкрдВрдЬреАрдХреГрдд рдЪрд╛рди * рдЧреНрд░рд╛рд╣рдХ
}
func newHub () рд╣рдм {рд╡рд╛рдкрд╕реА рдФрд░ рд╣рдм {рдкреНрд░рд╕рд╛рд░рдг: рдореЗрдХ (рдЪрд╛рди рд╕рдВрджреЗрд╢),рд░рдЬрд┐рд╕реНрдЯрд░: рдореЗрдХ (рдЪрд╛рди * рдХреНрд▓рд╛рдЗрдВрдЯ),рдЕрдкрдВрдЬреАрдХреГрдд: рдмрдирд╛рдУ (рдЪрд╛рди * рдЧреНрд░рд╛рд╣рдХ),рдЧреНрд░рд╛рд╣рдХ: рдмрдирд╛рдирд╛ (рдирдХреНрд╢рд╛ [ рдЧреНрд░рд╛рд╣рдХ] рдмреВрд▓),
}
}
рдлрдВрдХ (рдПрдЪ * рд╣рдм) рд░рди () {
рдХреЗ рд▓рд┐рдпреЗ {
рдЪреБрдирддреЗ рд╣реИрдВ {
рдорд╛рдорд▓рд╛ рдЧреНрд░рд╛рд╣рдХ: = <-h.register:
h.clients [рдЧреНрд░рд╛рд╣рдХ] = рд╕рдЪ
рдорд╛рдорд▓рд╛ рдЧреНрд░рд╛рд╣рдХ: = <-h.unregister:
рдЕрдЧрд░ _, рдареАрдХ: = h.clients [рдЧреНрд░рд╛рд╣рдХ]; рдареАрдХ рд╣реИ {
рд╣рдЯрд╛рдПрдВ (рдПрдЪред рдЧреНрд░рд╛рд╣рдХ, рдЧреНрд░рд╛рд╣рдХ)
рдмрдВрдж
}
рдорд╛рдорд▓рд╛ рд╕рдВрджреЗрд╢: = <-h.broadcast:
рдЧреНрд░рд╛рд╣рдХ рдХреЗ рд▓рд┐рдП: = рд╢реНрд░реЗрдгреА h.clients {
рдЕрдЧрд░ client.see == message.LogName {
client.send <- рд╕рдВрджреЗрд╢
}
//рдЪреБрдирддреЗ рд╣реИрдВ {
// рдХреЗрд╕ client.send <- рд╕рдВрджреЗрд╢:
//рдЪреВрдХ:
// рдмрдВрдж (client.send)
// рд╣рдЯрд╛рдПрдВ (рдПрдЪред рдЧреНрд░рд╛рд╣рдХ, рдЧреНрд░рд╛рд╣рдХ)
//}
}
}
}
}
func (c * рдХреНрд▓рд╛рдЗрдВрдЯ) readPump () {
рдбреЗрдлрд╝ рдлрдВрдХ () {
c.hub.unregister <- рд╕реА
_ = 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)); рд╡рд╛рдкрд╕ nil})
рдХреЗ рд▓рд┐рдпреЗ {
_, рд╕рдВрджреЗрд╢, рдЧрд▓рдд: = c.conn.ReadMessage ()
рдЕрдЧрд░ рдЧрд▓рдд рд╣реИ! = nil {
рдЕрдЧрд░ websocketред
ErrorLogger.Printf ("readPump рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рд╡рд┐рдлрд▓:% v", рдЗрд░)
}
рдЯреВрдЯрдирд╛
}
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 * рдХреНрд▓рд╛рдЗрдВрдЯ) рд░рд╛рдЗрдЯрдкрдВрдк () {
рдЯрд┐рдХрд░: = рд╕рдордп
рдбреЗрдлрд╝ рдлрдВрдХ () {
рдЯрд┐рдХрд░ .рдЯреЙрдк ()
_ = c.conn.Close ()
} ()
рдХреЗ рд▓рд┐рдпреЗ {
рдЪреБрдирддреЗ рд╣реИрдВ {
рдорд╛рдорд▓рд╛ рд╕рдВрджреЗрд╢, рдареАрдХ рд╣реИ: = <-send:
_ = c.conn.SetWriteDeadline (time.Now ()ред Add (writeWait)
рдЕрдЧрд░! рдареАрдХ рд╣реИ {
// рд╣рдм рдиреЗ рдЪреИрдирд▓ рдмрдВрдж рдХрд░ рджрд┐рдпрд╛ред
_ = 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 рд╕рд╣рдХрд░реНрдореА рд╕реЗ websocket рдЕрдиреБрд░реЛрдз рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИред
рдлрдВрдХ рд╕рд░реНрд╡реНрд╕ (рд╣рдм * рд╣рдм, рдбрдмреНрд▓реНрдпреВ http.esponseWriter, рдЖрд░ * http.Request) {
рдХреЙрди, рдЗрд░реЗрдЯ: = upgrader.Upgrad (w, r, nil)
рдЕрдЧрд░ рдЧрд▓рдд рд╣реИ! = nil {
log.Fatal (рдЗрд░реЗрдЯ)
рд╡рд╛рдкрд╕реА
}
рдЧреНрд░рд╛рд╣рдХ: = & рдЧреНрд░рд╛рд╣рдХ {рд╣рдм: рд╣рдм, рдХреЙрди: рдХреЙрди, рднреЗрдЬреЗрдВ: рдореЗрдХ (рдЪрд╛рди рд╕рдВрджреЗрд╢, 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()
}
рдХреНрдпрд╛ рдЖрдкрдХреЗ рдЧреНрд░рд╛рд╣рдХ рдХреЛ рдПрдХ рд╣реА рд╡реЗрдмрд╕реНрдХреЗрдЯ рд╕рдВрджреЗрд╢ рдореЗрдВ рдХрдИ JSON рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реЛрдВ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИ?
рдПрдХреНрд╕ / рдиреЗрдЯ / рд╡реЗрдмрд╕реЛрдХреЗрдЯ рдХреЗ рд╕рд╛рде рдХреЛрдб рджрд┐рдЦрд╛рдПрдВ рдЬреЛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред
рдХреНрдпрд╛ рдЖрдкрдХреЗ рдЧреНрд░рд╛рд╣рдХ рдХреЛ рдПрдХ рд╣реА рд╡реЗрдмрд╕реНрдХреЗрдЯ рд╕рдВрджреЗрд╢ рдореЗрдВ рдХрдИ JSON рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реЛрдВ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИ?
рдПрдХреНрд╕ / рдиреЗрдЯ / рд╡реЗрдмрд╕реЛрдХреЗрдЯ рдХреЗ рд╕рд╛рде рдХреЛрдб рджрд┐рдЦрд╛рдПрдВ рдЬреЛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред
рдирд╣реАрдВ рди
`` `рдкреИрдХреЗрдЬ рдореБрдЦреНрдп
рдЖрдпрд╛рдд (
"рдПрдиреНрдХреЛрдбрд┐рдВрдЧ / рдЬрд╕рди"
"golang.org/x/net/websocket"
"рдЖрдИрдУ"
)
// рд╡реЗрдмрд╕реЛрдХреЗрдЯ ховцИ╖ ховцИ╖
рдЯрд╛рдЗрдк рдХреНрд▓рд╛рдЗрдВрдЯ рд╕рдВрд░рдЪрдирд╛ {
рдЖрдИрдбреА рд╕реНрдЯреНрд░рд┐рдВрдЧ
рд╕реЙрдХреЗрдЯ * websocket.Conn
рдЪреИрди рд╕рдВрджреЗрд╢ рднреЗрдЬреЗрдВ
рд╕реНрдЯреНрд░рд┐рдВрдЧ рджреЗрдЦреЗрдВ
}
// члп ховцИ╖ члп
рдкреНрд░рдХрд╛рд░
рдХреНрд▓рд╛рдЗрдВрдЯ рдореИрдк [* рдХреНрд▓рд╛рдЗрдВрдЯ] рдмреВрд▓
рдЪреИрди рд╕рдВрджреЗрд╢ рдкреНрд░рд╕рд╛рд░рд┐рдд рдХрд░реЗрдВ
рд░рдЬрд┐рд╕реНрдЯрд░ рдЪрд╛рди * рдЧреНрд░рд╛рд╣рдХ
рдЕрдкрдВрдЬреАрдХреГрдд рдЪрд╛рди * рдЧреНрд░рд╛рд╣рдХ
}
var рдкреНрд░рдмрдВрдзрдХ = рдЧреНрд░рд╛рд╣рдХ рдкреНрд░рдмрдВрдзрдХ {
рдкреНрд░рд╕рд╛рд░рдг: рдореЗрдХ (рдЪрд╛рди рд╕рдВрджреЗрд╢),
рд░рдЬрд┐рд╕реНрдЯрд░: рдореЗрдХ (рдЪрд╛рди рдХреНрд▓рд╛рдЗрдВрдЯ),рдЕрдкрдВрдЬреАрдХреГрдд: рдмрдирд╛рдУ (рдЪрд╛рди * рдЧреНрд░рд╛рд╣рдХ),рдЧреНрд░рд╛рд╣рдХ: рдмрдирд╛рдирд╛ (рдирдХреНрд╢рд╛ [ рдЧреНрд░рд╛рд╣рдХ] рдмреВрд▓),
}
func (рдкреНрд░рдмрдВрдзрдХ * clientManager) рдкреНрд░рд╛рд░рдВрдн () {
рдбреЗрдлрд╝ рдлрдВрдХ () {
рдЕрдЧрд░ рдЧрд▓рдд рд╣реИ: = рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрдд (); рдЧрд╝рд▓рддреА рд╕реЗ! = 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) рд▓рд┐рдЦрдирд╛ () {
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 * рдХреНрд▓рд╛рдЗрдВрдЯ) рдкрдврд╝рд╛ () {
рдХреЗ рд▓рд┐рдпреЗ {
var рдЙрддреНрддрд░ рд╕реНрдЯреНрд░рд┐рдВрдЧ
рдЕрдЧрд░ рдЧрд▓рдд рд╣реИ: = websocket.Message.Receive (c.socket, & reply); рдЧрд╝рд▓рддреА рд╕реЗ! = nil {
рдЕрдЧрд░ рдЧрд▓рдд рд╣реИ! = io.EOF {
ErrorLogger.Printf ("% s", рдЗрд░реЗрдЯ)
manager.unregister <- рд╕реА
}
рдЯреВрдЯрдирд╛
}
рдЯрд╛рдЗрдк рдЖрд░рдИрд╡реА рд╕реНрдЯреНрд░рдХреНрдЪрд░ {
LogName рд╕реНрдЯреНрд░рд┐рдВрдЧ json:"logName"
}
var rcv = & recv {}
рдЕрдЧрд░ рдЧрд▓рдд рд╣реИ: = json.Unmarshal ([] рдмрд╛рдЗрдЯ (рдЙрддреНрддрд░), рдФрд░ рдЖрд░рд╕реАрд╡реА); рдЧрд╝рд▓рддреА рд╕реЗ! = nil {
manager.unregister <- рд╕реА
ErrorLogger.Printf ("% s", рдЗрд░реЗрдЯ)
рдЯреВрдЯрдирд╛
}
c.see = rcv.LogName
}
}
`` `
рдЧреЛрд░рд┐рд▓реНрд▓рд╛ рдкреИрдХреЗрдЬ рдореЗрдВ рдПрдХ рд╕реЗрдХрдВрдб рдореЗрдВ рдкреНрд░рд╕рд╛рд░рдг рд╕рдВрджреЗрд╢ рдХреА рд╕реАрдорд╛ рдирд╣реАрдВ рд╣реИред
рдпрджрд┐ рдЖрдкрдХрд╛ рдХреНрд▓рд╛рдЗрдВрдЯ рдХрд┐рд╕реА WebSocket рдореИрд╕реЗрдЬ рдореЗрдВ рдХрдИ JSON рдбреЙрдХреНрдпреВрдореЗрдВрдЯреНрд╕ рдХреЛ рд╣реИрдВрдбрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдирд╣реАрдВ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рдЕрдкрдиреЗ рдХреЛрдб рдХреЛ рд╣рдЯрд╛ рджреЗрдВ рдЬреЛ рдПрдХ рдореИрд╕реЗрдЬ рдореЗрдВ рдХрдИ рдбреЙрдХреНрдпреВрдореЗрдВрдЯреНрд╕ рд▓рд┐рдЦрддрд╛ рд╣реИред
рдЖрдкрдХрд╛ 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
}
}
}
рд╣рд╛рдВ, рдпрд╣ рдЖрдкрдХрд╛ рдХреЛрдб рд╣реИ рдЬреЛ рдПрдХ рд╡реЗрдмрд╕реИрдЯ рд╕рдВрджреЗрд╢ рдореЗрдВ рдХрдИ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдЬреЛрдбрд╝рддрд╛ рд╣реИред
рдареАрдХ рд╣реИ, рдХреНрдпрд╛ рдЧреЛрд░рд┐рд▓реНрд▓рд╛ рдХреЗ рдкрд╛рд╕ рдХреЛрдИ рдЪрд░ рдпрд╛ рдПрдкреАрдЖрдИ рд╣реИ рдЬреЛ рдЧреНрд░рд╛рд╣рдХ рдХреЛ рджреВрд╕рд░реЗ рд╕рдВрджреЗрд╢ рдореЗрдВ рдЕрдзрд┐рдХ рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ illa
рдЧреЛрд░рд┐рд▓реНрд▓рд╛ рдХреЗ рдкрд╛рд╕ рдПрдХ рдЪрд░ рдпрд╛ рдПрдкреАрдЖрдИ рдирд╣реАрдВ рд╣реИ рдЬреЛ рдкреНрд░рддрд┐ рд╕реЗрдХрдВрдб рд╕рдВрджреЗрд╢реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ рд╕реАрдорд┐рдд рдХрд░рддрд╛ рд╣реИред
рдПрдХ рдПрдХрд▓ рд╡реЗрдмрд╕рд░реНрдХреЗрдЯ рд╕рдВрджреЗрд╢ рдореЗрдВ рдХрдИ JSON рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реЛрдВ рдХреЛ рдкреИрдХ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдб рддрдм рдЯреНрд░рд┐рдЧрд░ рд╣реЛрдЧрд╛ рдЬрдм рд╕рдВрджреЗрд╢ рдмрд╣реБрдд рдЙрдЪреНрдЪ рджрд░ рдкрд░ рднреЗрдЬрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрд╣ рджреЗрдЦрддреЗ рд╣реБрдП рдХрд┐ рдЖрдкрдХреЗ рдЧреНрд░рд╛рд╣рдХ рдХреЛ рдПрдХ рд╣реА WebSocket рд╕рдВрджреЗрд╢ рдореЗрдВ рдХрдИ JSON рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реЛрдВ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЖрдк рдмрд╣реБрдд рдЕрдзрд┐рдХ рджрд░ рдкрд░ рд╕рдВрджреЗрд╢ рднреЗрдЬрддреЗ рд╕рдордп рдЕрдкрдиреЗ рдЖрд╡реЗрджрди рдХреЛ рд╕рдВрджреЗрд╢ рдЦреЛрдиреЗ рдХреА рдЙрдореНрдореАрдж рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рд╣рдЯрд╛рдП рдЧрдП рдХреЛрдб рдХреЛ рд╡рд╛рдкрд╕ рдЯрд┐рдкреНрдкрдгреА рдФрд░ рдкрд░реАрдХреНрд╖рдг рдХреЗ рдПрдХ рдЬреЛрдбрд╝реЗ рдХреЛ рдЙрджреНрдзреГрдд рдХрд░реЗрдВред
рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА
рдЧреЛрд░рд┐рд▓реНрд▓рд╛ рдХреЗ рдкрд╛рд╕ рдПрдХ рдЪрд░ рдпрд╛ рдПрдкреАрдЖрдИ рдирд╣реАрдВ рд╣реИ рдЬреЛ рдкреНрд░рддрд┐ рд╕реЗрдХрдВрдб рд╕рдВрджреЗрд╢реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ рд╕реАрдорд┐рдд рдХрд░рддрд╛ рд╣реИред
рдПрдХ рдПрдХрд▓ рд╡реЗрдмрд╕рд░реНрдХреЗрдЯ рд╕рдВрджреЗрд╢ рдореЗрдВ рдХрдИ JSON рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реЛрдВ рдХреЛ рдкреИрдХ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдб рддрдм рдЯреНрд░рд┐рдЧрд░ рд╣реЛрдЧрд╛ рдЬрдм рд╕рдВрджреЗрд╢ рдмрд╣реБрдд рдЙрдЪреНрдЪ рджрд░ рдкрд░ рднреЗрдЬрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрд╣ рджреЗрдЦрддреЗ рд╣реБрдП рдХрд┐ рдЖрдкрдХреЗ рдЧреНрд░рд╛рд╣рдХ рдХреЛ рдПрдХ рд╣реА WebSocket рд╕рдВрджреЗрд╢ рдореЗрдВ рдХрдИ JSON рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реЛрдВ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЖрдк рдмрд╣реБрдд рдЕрдзрд┐рдХ рджрд░ рдкрд░ рд╕рдВрджреЗрд╢ рднреЗрдЬрддреЗ рд╕рдордп рдЕрдкрдиреЗ рдЖрд╡реЗрджрди рдХреЛ рд╕рдВрджреЗрд╢ рдЦреЛрдиреЗ рдХреА рдЙрдореНрдореАрдж рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рд╣рдЯрд╛рдП рдЧрдП рдХреЛрдб рдХреЛ рд╡рд╛рдкрд╕ рдЯрд┐рдкреНрдкрдгреА рдФрд░ рдкрд░реАрдХреНрд╖рдг рдХреЗ рдПрдХ рдЬреЛрдбрд╝реЗ рдХреЛ рдЙрджреНрдзреГрдд рдХрд░реЗрдВред